package com.next

import grails.converters.JSON
import grails.gorm.transactions.Transactional
import org.springframework.security.access.annotation.Secured
import sun.misc.BASE64Encoder

import javax.annotation.security.PermitAll
import java.security.MessageDigest
import java.text.SimpleDateFormat
import org.grails.web.util.WebUtils

@Secured('permitAll')
@Transactional(readOnly = true)
class BocAppOpportunityController
{

    def springSecurityService
    def opportunityService
    def contactService
    def messageService
    def componentService
    def questionnaireInstanceService
    def attachmentsService
    def mailService

    def login()
    {
        println "login"
    }

    @Secured('permitAll')
    @Transactional
    def sendVerifiedCode()
    {
        String cellphone = params.cellphone
        if (!cellphone)
        {
            render([status: "error", errorMessage: '手机号码不能为空！'] as JSON)
            return
        }

        def user = User.findByCellphone(cellphone)
        if (!user)
        {
            render([status: "error", errorMessage: '用户不存在，请先完成后台录入！'] as JSON)
            return
        }

        // def verifyCode = contactService.generateVerifiedCode()
        def verifyCode = "123456"
        user.verificationCode = verifyCode
        user.save flush: true

        // def flag = messageService.sendVerifyMessage(cellphone, verifyCode)
        //def flag = componentService.evaluate(Component.findByName("中行发送验证码"),["verifiedCode":verifyCode,"cellphone":cellphone])
        def flag = true
        if (flag)
        {
            render([status: "success"] as JSON)
            return
        }
        else
        {
            render([status: "error", errorMessage: '短信验证码发送失败，请重试！'] as JSON)
            return
        }
    }

    @Secured('permitAll')
    @Transactional
    def sendVerifiedCodeToContact()
    {
        String cellphone = params.cellphone
        if (!cellphone)
        {
            render([status: "error", errorMessage: '手机号码不能为空！'] as JSON)
            return
        }
        def contact = Contact.findByCellphone(cellphone)
        if (!contact)
        {
            render([status: "error", errorMessage: '用户不存在，请先完成后台录入！'] as JSON)
            return
        }

        // def verifyCode = contactService.generateVerifiedCode()
        def verifyCode = "123456"
        contact.verifiedCode = verifyCode
        contact.cellphone = cellphone
        contact.save flush: true

        // def flag = messageService.sendVerifyMessage(cellphone, verifyCode)
        //def flag = componentService.evaluate(Component.findByName("中行发送验证码"),["verifiedCode":verifyCode,"cellphone":cellphone])
        def flag = true
        if (flag)
        {
            render([status: "success"] as JSON)
            return
        }
        else
        {
            render([status: "error", errorMessage: '短信验证码发送失败，请重试！'] as JSON)
            return
        }
    }

    @Secured('permitAll')
    @Transactional
    def sendVerifiedCodeForAuthorize(Opportunity opportunity)
    {
        String cellphone = params.cellphone
        if (!cellphone)
        {
            render([status: "error", errorMessage: '手机号码不能为空！'] as JSON)
            return
        }

        def contact = opportunity?.contact
        if (!contact)
        {
            contact = new Contact()
        }
        // def verifyCode = contactService.generateVerifiedCode()
        def verifyCode = "123456"
        contact.verifiedCode = verifyCode
        contact.cellphone = cellphone
        contact.save flush: true
        opportunity.contact = contact
        opportunity.save flush: true
        // def flag = messageService.sendVerifyMessage(cellphone, verifyCode)
        //def flag = componentService.evaluate(Component.findByName("中行发送验证码"),["verifiedCode":verifyCode,"cellphone":cellphone])
        def flag = true
        if (flag)
        {
            render([status: "success"] as JSON)
            return
        }
        else
        {
            render([status: "error", errorMessage: '短信验证码发送失败，请重试！'] as JSON)
            return
        }
    }

    @Secured('permitAll')
    @Transactional
    def sendVerifiedCodeForSpouseAuthorize(Opportunity opportunity)
    {
        String cellphone = params.cellphone
        if (!cellphone)
        {
            render([status: "error", errorMessage: '手机号码不能为空！'] as JSON)
            return
        }

        def contact = OpportunityContact.findByOpportunityAndType(opportunity, OpportunityContactType.findByName('借款人配偶'))?.contact
        if (!contact)
        {
            contact = new Contact()
            // def verifyCode = contactService.generateVerifiedCode()
            def verifyCode = "123456"
            contact.verifiedCode = verifyCode
            contact.cellphone = cellphone
            contact.save flush: true

            def opportunityContact = new OpportunityContact()
            opportunityContact.opportunity = opportunity
            opportunityContact.contact = contact
            opportunityContact.type = OpportunityContactType.findByName("借款人配偶")
            if (opportunityContact.validate())
            {
                opportunityContact.save flush: true
            }
            else
            {
                println opportunityContact.errors
            }
        }
        else
        {
            // def verifyCode = contactService.generateVerifiedCode()
            def verifyCode = "123456"
            contact.verifiedCode = verifyCode
            contact.cellphone = cellphone
            contact.save flush: true
        }

        // def flag = messageService.sendVerifyMessage(cellphone, verifyCode)
        //def flag = componentService.evaluate(Component.findByName("中行发送验证码"),["verifiedCode":verifyCode,"cellphone":cellphone])
        def flag = true
        if (flag)
        {
            render([status: "success"] as JSON)
            return
        }
        else
        {
            render([status: "error", errorMessage: '短信验证码发送失败，请重试！'] as JSON)
            return
        }
    }

    @Secured('permitAll')
    @Transactional
    def loginVerifyCode()
    {
        // 通过手机号码获取用户信息
        User user = User.findByCellphone(params["cellphone"])
        if (user)
        {
            if (user.verificationCode != params["verificationCode"])
            {
                flash.message = '验证码验证失败'
                respond user, view: 'login'
            }
            else
            {
                user.appSessionId = UUID.randomUUID().toString()
                user.save flush: true

                redirect(action: "show", params: [code: null, state: null, id: user.id])
                return
            }
        }
        else
        {
            flash.message = '客户经理不存在，请先完成后台录入！'
            respond user, view: 'login'
        }
    }

    def getAccountByChannelId()
    {
        def channel = params["channel"]
        if (!channel || channel == '-1' || channel == 'null')
        {
            return ''
        }
        else
        {
            channel = Long.parseLong(channel)
            render([accountList: Account.executeQuery("select a.id as id, a.name as name from Account a where a.parent.id = ${channel} and a.type.name = '商户'")] as JSON)
        }
    }

    def getProductByAccountId()
    {
        def account = params["account"]
        if (!account || account == '-1' || account == 'null')
        {
            return ''
        }
        else
        {
            account = Long.parseLong(account)
            render([productList: ProductAccount.executeQuery("select p.product.id as id, p.product.name as name from ProductAccount p where p.account.id = ${account} and p.account.type.name = '商户'")] as JSON)
        }
    }

    def getAccountByProductId()
    {
        def product = params["product"]
        if (!product || product == '-1' || product == 'null')
        {
            return ''
        }
        else
        {
            product = Long.parseLong(product)
            render([productList: ProductAccount.executeQuery("select p.account.id as id, p.account.name as name from ProductAccount p where p.product.id = ${product} and p.account.type.name = '商户'")] as JSON)
        }
    }

    @Transactional
    def createOpportunitySave(Opportunity opportunity)
    {
        def username = springSecurityService.getPrincipal().username
        def user = User.findByUsername(username)

        def fullName = params.fullName
        def idNumber = params.idNumber ? params.idNumber.toString() : ''
        def cellphone = params.cellphone ? params.cellphone?.toString() : ''

        def contact = Contact.findByCellphone(cellphone)
        if (!contact)
        {
            contact = new Contact()
        }
        contact.fullName = fullName
        contact.idNumber = idNumber
        contact.cellphone = cellphone
        if (contact.validate())
        {
            contact.save flush: true
        }
        else
        {
            println contact.errors
        }

        opportunity.user = user
        opportunity.contact = contact
        if (opportunity.validate())
        {
            opportunity.save flush: true
        }
        else
        {
            println opportunity.errors
        }

        def opportunityContact = new OpportunityContact()
        opportunityContact.opportunity = opportunity
        opportunityContact.contact = contact
        opportunityContact.type = OpportunityContactType.findByName("借款人")
        if (opportunityContact.validate())
        {
            opportunityContact.save flush: true
        }
        else
        {
            println opportunityContact.errors
        }

        // 初始化
        opportunityService.initOpportunity(opportunity)

        def mobileLayout = WorkflowInstance.findByOpportunityAndStatus(opportunity, WorkflowInstanceStatus.findByName('Pending'))?.stage?.mobileLayout?.name
        if (mobileLayout)
        {
            redirect action: mobileLayout, id: opportunity?.id
            return
        }
        else
        {
            redirect action: 'businessManagement'
        }
    }

    // 身份验证页面
    def identityVerification(Opportunity opportunity)
    {
        respond opportunity
    }

    //身份验证保存
    @Transactional
    def identityVerificationSave(Opportunity opportunity)
    {
        def attachments1 = new Attachments()
        attachments1.opportunity = opportunity
        attachments1.type = AttachmentType.findByName("借款人身份证正面")
        attachments1.fileName = "http://quickloanfs.cindata.cn/" + params?.idcardPositiveUrl
        attachments1.thumbnailUrl = "http://quickloanfs.cindata.cn/" + params?.idcardPositiveUrl
        attachments1.fileUrl = "http://quickloanfs.cindata.cn/" + params?.idcardPositiveUrl
        if (attachments1.validate())
        {
            attachments1.save flush: true
        }
        else
        {
            println attachments1.errors
        }

        def attachments2 = new Attachments()
        attachments2.opportunity = opportunity
        attachments2.type = AttachmentType.findByName("借款人身份证反面")
        attachments2.fileName = "http://quickloanfs.cindata.cn/" + params?.idcardNegativeUrl
        attachments2.thumbnailUrl = "http://quickloanfs.cindata.cn/" + params?.idcardNegativeUrl
        attachments2.fileUrl = "http://quickloanfs.cindata.cn/" + params?.idcardNegativeUrl
        if (attachments2.validate())
        {
            attachments2.save flush: true
        }
        else
        {
            println attachments2.errors
        }

        //保存联系人信息
        def contact = Contact.findByIdNumber(params?.idNumber)
        if (!contact)
        {
            contact = new Contact()
        }
        contact.fullName = params?.fullName
        contact.maritalStatus = params?.maritalStatus
        contact.identityType = ContactIdentityType.findByName("个人居民身份证")
        contact.idNumber = params?.idNumber
        contact.gender = params?.gender
        contact.nation = params?.nation
        contact.nativePlace = params?.nativePlace
        contact.periodOfValidity = params?.periodOfValidity
        contact.authority = params?.authority
        contact.age = getAge(params?.idNumber)

        if (params?.birthday)
        {
            contact.birthday = new SimpleDateFormat("yyyy年MM月dd日").parse(params?.birthday)
        }
        if (contact.validate())
        {
            contact.save flush: true
        }
        else
        {
            println contact.errors
        }

        def opportunityContact = new OpportunityContact()
        opportunityContact.opportunity = opportunity
        opportunityContact.contact = contact
        opportunityContact.type = OpportunityContactType.findByName("借款人")
        if (opportunityContact.validate())
        {
            opportunityContact.save flush: true
        }
        else
        {
            println opportunityContact.errors
        }

        opportunity.contact = contact
        opportunity.save flush: true

        contactApprove(opportunity)
    }

    // 授信成功页面
    @Transactional
    def successful(Opportunity opportunity)
    {
        //        opportunity.maximumAmountOfCredit = 1200000.0
        //        opportunity.commissionRate = 0.0178
        //        opportunity.commission = 1200000 * 0.0178
        //        opportunity?.save flush: true
        respond opportunity
    }

    @Transactional
    def successfulListSave(Opportunity opportunity)
    {
        String name = params.checkbox1
        if (name)
        {
            def opportunityFlexField = OpportunityFlexField.findByNameAndCategory(name, OpportunityFlexFieldCategory.findByOpportunityAndFlexFieldCategory(opportunity, FlexFieldCategory.findByName("额度测算结果")))
            if (opportunityFlexField)
            {
                // 百融授信额度
                opportunity.maximumAmountOfCredit = Double.parseDouble(opportunityFlexField?.value ? opportunityFlexField?.value : "0")
                // 百融总费率(客户费率 + 厂商贴息费率)
                opportunity.ompositeMonthlyInterest = Double.parseDouble(opportunityFlexField?.defaultValue ? opportunityFlexField?.defaultValue : "0")
                // 手续费 = 授信额度 * 客户费率，暂时将总费率赋值给客户费率，厂商贴息为0，页面中由客户经理自行调整
                opportunity.commission = opportunity.maximumAmountOfCredit * opportunity.ompositeMonthlyInterest
                opportunity.verifyMaterial = opportunityFlexField?.description
                opportunity?.save()

                // 初始化验证材料
                initVerifyMaterial(opportunity)

                //推进阶段
                approveStage(opportunity)
            }
            else
            {
                println("选择的产品没保存？")
                render("选择的产品没保存？")
            }
        }
        else
        {
            render("提交选择失败")
        }
    }

    @Transactional
    def initVerifyMaterial(Opportunity opportunity)
    {
        def opportunityFlexFieldCategory = OpportunityFlexFieldCategory.findByOpportunityAndFlexFieldCategory(opportunity, FlexFieldCategory.findByName("材料核验"))
        if (opportunity?.verifyMaterial)
        {
            def verifyMaterialList = opportunity?.verifyMaterial?.split("、")
            for (
                def verifyItem :
                    verifyMaterialList)
            {
                opportunityFlexFieldCategory?.fields?.each {
                    if (it?.name == verifyItem)
                    {
                        it?.value = "是"
                        it.save flush: true
                    }
                }
            }
        }
    }

    @Transactional
    def successfulSave(Opportunity opportunity)
    {
        def workflowInstance = WorkflowInstance.findByOpportunityAndStatus(opportunity, WorkflowInstanceStatus.findByName('Pending'))
        approve(workflowInstance)
        def mobileLayout = workflowInstance?.stage?.mobileLayout?.name
        redirect action: mobileLayout, id: opportunity?.id
    }

    // 业务管理
    def businessManagement()
    {
        def username = springSecurityService.getPrincipal().username
        def user = User.findByUsername(username)
        println user
        def opportunityCount = (Long) Opportunity.executeQuery("select count(1) from Opportunity o where o.user=${user}")[0]
        render(model: [user: user, count: opportunityCount], view: 'businessManagement')
    }

    // 业务办理-订单
    def businessTransaction()
    {
        def username = springSecurityService.getPrincipal().username
        def user = User.findByUsername(username)

        def sql = "from Opportunity o where o.user.id = ${user?.id}"
        def estateQueryParam = new HashMap()
        def query = params.query
        if (query)
        {
            sql += " and (lower(o.serialNumber) like lower(:query1) or lower(o.contact.cellphone) like lower(:query2)or lower(o.contact.fullName) like lower(:query3))"
            estateQueryParam['query1'] = '%' + query + '%'
            estateQueryParam['query2'] = '%' + query + '%'
            estateQueryParam['query3'] = '%' + query + '%'
        }

        sql += " order by o.createdDate desc"
        def opportunityList = Opportunity.executeQuery(sql, estateQueryParam)
        respond opportunityList, model: [params: params]
    }

    // 业务办理-订单详情
    def businessTransactionOpportunity(Opportunity opportunity)
    {
        def workflowInstance = WorkflowInstance.findByOpportunity(opportunity)
        def curerentStageNumber = workflowInstance.stage.executionSequence
        def curerentStageStatus = workflowInstance.status?.name
        def workflowInstanceStageList = WorkflowInstanceStage.findAllByInstance(workflowInstance, [sort: 'executionSequence', order: 'desc'])

        respond opportunity, model: [workflowInstanceStageList: workflowInstanceStageList, curerentStageNumber: curerentStageNumber, curerentStageStatus: curerentStageStatus]
    }

    def faceRecognition(Opportunity opportunity)
    {
        respond opportunity, model: [contact: opportunity?.contact], view: 'faceRecognition'
    }

    def spouseFaceRecognition(Opportunity opportunity)
    {
        respond opportunity, model: [contact: OpportunityContact.findByOpportunityAndType(opportunity, OpportunityContactType.findByName('借款人配偶'))?.contact, type: 'spouse'], view: 'faceRecognition'
    }

    def faceRecognitionSuccess(Opportunity opportunity)
    {
        def fileUrl = params.fileUrl
        def type = AttachmentType.findByName("人脸对比照")
        if (fileUrl && type)
        {
            fileUrl = "http://quickloanfs.cindata.cn/" + fileUrl

            new Attachments(opportunity: opportunity, type: type, fileUrl: fileUrl, fileName: fileUrl, thumbnailUrl: fileUrl, description: "人脸识别照片").save(flush: true)
        }
        respond opportunity, model: ["score": params.score, params: params]
    }

    def faceRecognitionFailed(Opportunity opportunity)
    {
        respond opportunity, model: [params: params]
    }

    //订单详情重新提交按钮
    def reSubmit(Opportunity opportunity)
    {
        def username = springSecurityService.getPrincipal().username
        def user = User.findByUsername(username)
        if (!user)
        {
            redirect action: 'login'
            return
        }

        def workflowInstance = WorkflowInstance.findByOpportunityAndStatus(opportunity, WorkflowInstanceStatus.findByName('Pending'))
        def authority = WorkflowAuthority.find("from WorkflowAuthority where name = :name", [name: "Approval"])
        def workflowInstanceUser = WorkflowInstanceUser.find("from WorkflowInstanceUser where stage.id = ${workflowInstance?.stage?.id} and user.id = ${user?.id} and authority.id = ${authority?.id}")
        if (!workflowInstanceUser)
        {
            flash.message = "对不起，您没有权限！"
            redirect action: 'businessTransactionOpportunity', id: opportunity?.id
            return
        }
        def mobileLayout = workflowInstance?.stage?.mobileLayout?.name
        if (mobileLayout)
        {
            redirect action: mobileLayout, id: opportunity?.id
            return
        }
        else
        {
            render "对不起，页面不存在！"
            return
        }
    }

    //合影信息页面
    def visaInterviewStep1(Opportunity opportunity)
    {
        respond opportunity
    }

    @Transactional
    def visaInterviewStep1Save(Opportunity opportunity)
    {
        def attachments = new Attachments()
        attachments.opportunity = opportunity
        attachments.type = AttachmentType.findByName("面签")
        attachments.fileName = "http://quickloanfs.cindata.cn/" + params?.fileUrl
        attachments.thumbnailUrl = "http://quickloanfs.cindata.cn/" + params?.fileUrl
        attachments.fileUrl = "http://quickloanfs.cindata.cn/" + params?.fileUrl
        attachments.latitude = params?.latitude?.toDouble()
        attachments.longitude = params?.longitude?.toDouble()
        attachments.address = params?.address

        if (attachments.validate())
        {
            attachments.save flush: true
        }
        else
        {
            println attachments.errors
        }

        approveStage(opportunity)
    }

    def businessApplication(Opportunity opportunity)
    {
        respond opportunity
    }

    @Transactional
    def businessApplicationSave(Opportunity opportunity)
    {

        batchAttachmentInsert(opportunity, params?.attachmentUrl, "分期业务综合申请表")

        approveStage(opportunity)
    }

    def sequelBusiness1(Opportunity opportunity)
    {
        respond opportunity
    }

    def sequelBusiness2(Opportunity opportunity)
    {
        respond opportunity
    }

    def sequelBusiness3(Opportunity opportunity)
    {
        respond opportunity
    }

    @Transactional
    def contactApprove(Opportunity opportunity)
    {
        def workflowInstance = WorkflowInstance.findByOpportunityAndStatus(opportunity, WorkflowInstanceStatus.findByName('Pending'))
        def result = workflowInstanceService.approve(workflowInstance)
        if (result?.flag)
        {
            def mobileLayout = workflowInstance?.stage?.mobileLayout?.name
            if (mobileLayout && workflowInstance?.stage?.type == "public")
            {
                redirect action: mobileLayout, id: opportunity?.id
                return
            }
            else
            {
                // 客户操作成功页面
                redirect action: 'contactSuccess'
                return
            }
        }
        else
        {
            render result?.message
            return
        }
    }

    @Transactional
    def approve1(Opportunity opportunity)
    {
        def username = springSecurityService.getPrincipal().username
        def user = User.findByUsername(username)
        if (!user)
        {
            redirect action: 'login'
            return
        }

        def workflowInstance = WorkflowInstance.findByOpportunityAndStatus(opportunity, WorkflowInstanceStatus.findByName('Pending'))
        def result = approve(workflowInstance)
        if (result?.flag)
        {
            def mobileLayout = workflowInstance?.stage?.mobileLayout?.name
            if (mobileLayout)
            {
                redirect action: mobileLayout, id: opportunity?.id
                return
            }
        }
        redirect action: 'businessTransactionOpportunity', id: opportunity?.id

    }

    @Transactional
    def approveStage(Opportunity opportunity)
    {
        def username = springSecurityService.getPrincipal().username
        def user = User.findByUsername(username)
        if (!user)
        {
            redirect action: 'login'
            return
        }

        def workflowInstance = WorkflowInstance.findByOpportunityAndStatus(opportunity, WorkflowInstanceStatus.findByName('Pending'))
        def currentMobileLayout = workflowInstance?.stage?.mobileLayout?.name
        def result = workflowInstanceService.approve(workflowInstance, user)
        if (result?.flag)
        {
            def authority = WorkflowAuthority.find("from WorkflowAuthority where name = :name", [name: "Approval"])
            def workflowInstanceUser = WorkflowInstanceUser.find("from WorkflowInstanceUser where stage.id = ${workflowInstance?.stage?.id} and user.id = ${user?.id} and authority.id = ${authority?.id}")
            if (!workflowInstanceUser)
            {
                flash.message = "操作成功，请等待下一阶段人员处理"
                redirect action: 'businessTransactionOpportunity', id: opportunity?.id
                return
            }
            def mobileLayout = workflowInstance?.stage?.mobileLayout?.name
            if (mobileLayout)
            {
                redirect action: mobileLayout, id: opportunity?.id
                return
            }
            else
            {
                render "对不起，页面不存在"
                return
            }
        }
        else
        {
            if (result?.message == "工作流已结束")
            {
                flash.message = "操作成功，请等待下一阶段人员处理"
                redirect action: 'businessTransactionOpportunity', id: opportunity?.id
                return
            }
            else
            {
                flash.message = result?.message
                respond opportunity, view: currentMobileLayout
                return
            }
        }
    }

    @Transactional
    def reject(Opportunity opportunity)
    {
        def memo = params?.memo
        opportunity.memo = memo
        opportunity.save flush: true

        def workflowInstance = WorkflowInstance.findByOpportunityAndStatus(opportunity, WorkflowInstanceStatus.findByName('Pending'))
        workflowInstance.status = WorkflowInstanceStatus.findByName('Failed')
        workflowInstance.save flush: true

        render([status: "success"] as JSON)
    }

    @Transactional
    def approve(WorkflowInstance workflowInstance)
    {
        def result = [:]
        if (workflowInstance?.status?.name != "Pending")
        {
            result['flag'] = false
            result['message'] = '工作流已结束！'
            return result
        }

        def workflowInstanceStage = workflowInstance?.stage
        if (!workflowInstanceStage)
        {
            result['flag'] = false
            result['message'] = "找不到工作流"
            return result
        }

        def executionSequence = workflowInstanceStage?.executionSequence
        def nextWorkflowInstanceStage = WorkflowInstanceStage.find("from WorkflowInstanceStage where instance.id = ? and executionSequence > ? order by executionSequence ASC", [workflowInstance?.id, executionSequence])
        if (!nextWorkflowInstanceStage)
        {
            workflowInstance.status = WorkflowInstanceStatus.findByName('Completed')
            workflowInstance.save flush: true
            result['flag'] = false
            result['message'] = "找不到下个阶段工作流"
            return result
        }

        workflowInstance.stage = nextWorkflowInstanceStage
        workflowInstance.save flush: true

        result['flag'] = true
        result['message'] = "成功"

        return result
    }

    @Transactional
    def questionnaireSurvey(Opportunity opportunity)
    {
        // 初始化问卷
        questionnaireInstanceService.initQuestionnaireInstance(opportunity)

        def questionnaireInstance = QuestionnaireInstance.findByTypeAndOpportunity(QuestionnaireType.findByName(opportunity?.product?.name), opportunity)
        respond opportunity, model: [questionnaireInstance: questionnaireInstance]
    }

    def questionnaireSurveySave(Opportunity opportunity)
    {
        def questionnaireInstanceId = params['questionnaireInstanceId']
        def questionnaireInstance = QuestionnaireInstance.findById(questionnaireInstanceId)
        questionnaireInstance?.questions?.each { question ->
            if (question?.questionType == "input")
            {
                def questionValue = params[question?.name]
                if (questionValue)
                {
                    question?.value = questionValue
                    if (question?.validate())
                    {
                        question.save flush: true
                    }
                    else
                    {
                        println question.errors
                    }
                }
            }

            if (question?.questionType == "radio")
            {
                OptionInstance.findAllByQuestionInstance(question)?.each { option ->
                    def optionName = params[question?.name]
                    if (option?.name == optionName)
                    {
                        option?.selected = true
                        if (option?.validate())
                        {
                            option.save flush: true
                        }
                        else
                        {
                            println option.errors
                        }
                    }
                }
            }

            if (question?.questionType == "checkbox")
            {
                OptionInstance.findAllByQuestionInstance(question)?.each { option ->
                    def optionValue = params[option?.name]
                    if (optionValue)
                    {
                        option?.selected = optionValue
                        if (option?.validate())
                        {
                            option.save flush: true
                        }
                        else
                        {
                            println option.errors
                        }
                    }
                }
            }
        }

        approveStage(opportunity)
    }

    def login2()
    {
    }

    def isLogIn()
    {
        if (springSecurityService.isLoggedIn())
        {
            render([status: "success"] as JSON)
        }
        else
        {
            render([status: "error"] as JSON)
        }
    }

    def remoteSignfaceStep1(Opportunity opportunity)
    {
        respond opportunity
    }

    def remoteSignfaceStep2(Opportunity opportunity)
    {
        respond opportunity
    }

    // --------------------------------------- 第二版 ----------------------------------------//
    def createOpportunityInfo()
    {
        def username = springSecurityService.getPrincipal().username
        def user = User.findByUsername(username)

        def opportunity = new Opportunity()
        def channelList = []
        if (user?.type?.name == "机构柜员")
        {
            def accountList = AccountTeam.executeQuery("select a.account from AccountTeam a where a.user.id = ${user?.id} and a.account.type.name = '机构' and a.account.active = true")
            if (accountList)
            {
                channelList = Account.findAllByParentInListAndTypeAndActive(accountList, AccountType.findByName('渠道'), true)
            }
        }

        def territory = TerritoryAccount.findByAccount(user?.account)?.territory
        def productList = TerritoryProduct.findAllByTerritory(territory)*.product
        respond opportunity, model: [channelList: channelList, productList: productList]
    }

    @Transactional
    def createOpportunityInfoSave(Opportunity opportunity)
    {
        def username = springSecurityService.getPrincipal().username
        def user = User.findByUsername(username)

        opportunity.user = user
        if (opportunity.validate())
        {
            opportunity.save flush: true
        }
        else
        {
            println opportunity.errors
        }

        // 初始化
        opportunityService.initOpportunity(opportunity)

        redirect action: 'copyUrl', id: opportunity?.id
    }

    def copyUrl(Opportunity opportunity)
    {
        def hostAddress = WebUtils.retrieveGrailsWebRequest().getBaseUrl()
        def url = "${hostAddress}/bocAppOpportunity/contactUrl/${opportunity?.id}"
        respond opportunity, model: [url: url]
    }

    def workflowInstanceService

    def contactUrl(Opportunity opportunity)
    {
        def workflowInstance = WorkflowInstance.findByOpportunityAndStatus(opportunity, WorkflowInstanceStatus.findByName('Pending'))
        if (workflowInstance?.stage?.type != 'public')
        {
            render "对不起，页面不存在"
            return
        }
        def mobileLayout = workflowInstance?.stage?.mobileLayout?.name
        if (mobileLayout)
        {
            redirect action: mobileLayout, id: opportunity?.id
            return
        }
        else
        {
            render "对不起，页面不存在"
            return
        }
    }

    //汽车 客户信息简易申请表
    def contactApplicationInfo(Opportunity opportunity)
    {
        respond opportunity
    }

    //优客 客户信息简易申请表
    def contactApplicationInfo2(Opportunity opportunity)
    {
        respond opportunity
    }

    //车位 客户信息简易申请表
    def contactApplicationInfo3(Opportunity opportunity)
    {
        respond opportunity
    }

    //家装 客户信息简易申请表
    def contactApplicationInfo4(Opportunity opportunity)
    {
        respond opportunity
    }

    @Transactional
    def contactApplicationInfoSave(Opportunity opportunity)
    {
        // 保存商品品牌 型号 商品总价
        opportunity.requestedAmount = Double.parseDouble(params?.requestedAmount)
        opportunity.loanAmount = Double.parseDouble(params?.loanAmount)
        opportunity.brand = params?.brand
        opportunity.marque = params?.marque
        opportunity.loanDuration = Integer.parseInt(params?.loanDuration)
        if (opportunity.validate())
        {
            opportunity.save flush: true
        }
        else
        {
            println opportunity.errors
        }

        contactApprove(opportunity)
    }

    //配偶身份证验证页面
    def spouseIdentityVerification(Opportunity opportunity)
    {
        respond opportunity
    }

    @Transactional
    def spouseIdentityVerificationSave(Opportunity opportunity)
    {
        def attachments1 = new Attachments()
        attachments1.opportunity = opportunity
        attachments1.type = AttachmentType.findByName("借款人配偶身份证正面")
        attachments1.fileName = "http://quickloanfs.cindata.cn/" + params?.idcardPositiveUrl
        attachments1.thumbnailUrl = "http://quickloanfs.cindata.cn/" + params?.idcardPositiveUrl
        attachments1.fileUrl = "http://quickloanfs.cindata.cn/" + params?.idcardPositiveUrl
        if (attachments1.validate())
        {
            attachments1.save flush: true
        }
        else
        {
            println attachments1.errors
        }

        def attachments2 = new Attachments()
        attachments2.opportunity = opportunity
        attachments2.type = AttachmentType.findByName("借款人配偶身份证反面")
        attachments2.fileName = "http://quickloanfs.cindata.cn/" + params?.idcardNegativeUrl
        attachments2.thumbnailUrl = "http://quickloanfs.cindata.cn/" + params?.idcardNegativeUrl
        attachments2.fileUrl = "http://quickloanfs.cindata.cn/" + params?.idcardNegativeUrl
        if (attachments2.validate())
        {
            attachments2.save flush: true
        }
        else
        {
            println attachments2.errors
        }

        //保存借款人配偶
        def contact = Contact.findByIdNumber(params?.idNumber)
        if (!contact)
        {
            contact = new Contact()
        }
        contact.fullName = params?.fullName
        contact.maritalStatus = params?.maritalStatus
        contact.identityType = ContactIdentityType.findByName("个人居民身份证")
        contact.idNumber = params?.idNumber
        contact.gender = params?.gender
        contact.nation = params?.nation
        contact.nativePlace = params?.nativePlace
        contact.periodOfValidity = params?.periodOfValidity
        contact.authority = params?.authority
        contact.age = getAge(params?.idNumber)
        if (params?.birthday)
        {
            contact.birthday = new SimpleDateFormat("yyyy年MM月dd日").parse(params?.birthday)
        }

        def opportunityContact = new OpportunityContact()
        opportunityContact.opportunity = opportunity
        opportunityContact.contact = contact
        opportunityContact.type = OpportunityContactType.findByName("借款人配偶")
        if (opportunityContact.validate())
        {
            opportunityContact.save flush: true
        }
        else
        {
            println opportunityContact.errors
        }

        contactApprove(opportunity)
    }

    //欺诈决策
    def fraudDecision(Opportunity opportunity)
    {
        def result
        def map = [:]
        map.opportunity = opportunity
        map.type = ""
        def result1 = componentService.evaluate(Component.findByName("百融进件规则"), map)
        println "百融进件规则结果：" + result1
        def opportunityFlexField = com.next.OpportunityFlexField.findByNameAndCategory("百融欺诈决策结果", com.next.OpportunityFlexFieldCategory.findByOpportunityAndFlexFieldCategory(opportunity, com.next.FlexFieldCategory.findByName("百融欺诈决策结果")))

        if (opportunityFlexField)
        {
            result = opportunityFlexField.value
        }
        respond opportunity, model: [result: result]
    }

    //欺诈决策
    def spouseFraudDecision(Opportunity opportunity)
    {
        def result
        def map = [:]
        map.opportunity = opportunity
        map.type = "spouse"
        def result1 = componentService.evaluate(Component.findByName("百融进件规则"), map)
        println "百融进件规则结果：" + result1
        def opportunityFlexField = com.next.OpportunityFlexField.findByNameAndCategory("百融欺诈决策结果", com.next.OpportunityFlexFieldCategory.findByOpportunityAndFlexFieldCategory(opportunity, com.next.FlexFieldCategory.findByName("百融欺诈决策结果")))

        if (opportunityFlexField)
        {
            result = opportunityFlexField.value
        }
        respond opportunity, model: [result: result, type: 'spouse'], view: 'fraudDecision'
    }

    def fraudDecisionSuccess(Opportunity opportunity)
    {
        def contact = opportunity?.contact
        if (params?.type == 'spouse')
        {
            contact = OpportunityContact.findByOpportunityAndType(opportunity, OpportunityContactType.findByName('借款人配偶'))?.contact
        }
        respond opportunity, model: [contact: contact]
    }

    def fraudDecisionFailed(Opportunity opportunity)
    {
        respond opportunity
    }

    //电子签名
    def signature(Opportunity opportunity)
    {
        respond opportunity
    }

    def spouseSignature(Opportunity opportunity)
    {
        respond opportunity, model: [type: 'spouse'], view: 'signature'
    }

    //电子签名
    def signature1(Opportunity opportunity)
    {
        respond opportunity
    }

    @Transactional
    def signatureSave(Opportunity opportunity)
    {
        // TODO
        contactApprove(opportunity)
    }

    //征信授权
    def creditAuthorize(Opportunity opportunity)
    {
        respond opportunity, model: [contact: opportunity?.contact]
    }

    def spouseCreditAuthorize(Opportunity opportunity)
    {
        respond opportunity, model: [contact: OpportunityContact.findByOpportunityAndType(opportunity, OpportunityContactType.findByName('借款人配偶'))?.contact, type: 'spouse'], view: 'creditAuthorize'
    }

    //业务申请表
    def creditAuthorize1(Opportunity opportunity)
    {
        respond opportunity
    }

    @Transactional
    def creditAuthorizeSave(Opportunity opportunity)
    {
        def verifiedCode = params?.verifiedCode
        if (verifiedCode != opportunity?.contact?.verifiedCode)
        {
            flash.message = "验证码验证失败"
            respond opportunity, view: 'creditAuthorize'
            return
        }

        contactApprove(opportunity)
    }

    @Transactional
    def contactBaseInfo(Opportunity opportunity)
    {
        respond opportunity
    }

    @Transactional
    def contactBaseInfoSave(Opportunity opportunity)
    {
        if (params?.housingFundPersonalRatio)
        {
            opportunity.contact.housingFundPersonalRatio = params?.housingFundPersonalRatio?.toDouble() / 100
        }
        if (params?.socialInsurancePersonalRatio)
        {
            opportunity.contact.socialInsurancePersonalRatio = params?.socialInsurancePersonalRatio?.toDouble() / 100
        }
        if (params?.individualIncomeTaxPersonalRatio)
        {
            opportunity.contact.individualIncomeTaxPersonalRatio = params?.individualIncomeTaxPersonalRatio?.toDouble() / 100
        }

        if (opportunity.contact.validate())
        {
            opportunity.contact.save flush: true
        }
        else
        {
            println opportunity.contact.errors
        }

        if (params?.house1?.address && params?.house1?.area)
        {
            def house1 = new House(params?.house1)
            if (house1.validate())
            {
                house1.save flush: true
            }
            else
            {
                println house1.errors
            }
        }
        if (params?.house2?.address && params?.house2?.area)
        {
            def house2 = new House(params?.house2)
            if (house2.validate())
            {
                house2.save flush: true
            }
            else
            {
                println house2.errors
            }
        }
        if (params?.house3?.address && params?.house3?.area)
        {
            def house3 = new House(params?.house3)
            if (house3.validate())
            {
                house3.save flush: true
            }
            else
            {
                println house3.errors
            }
        }

        redirect action: 'contactProfessionalInfo', id: opportunity?.id
    }

    // 客户职业信息
    def contactProfessionalInfo(Opportunity opportunity)
    {
        respond opportunity
    }

    @Transactional
    def contactProfessionalInfoSave(Opportunity opportunity)
    {
        if (params?.workTime)
        {
            opportunity.contact.workTime = new SimpleDateFormat("yyyy-MM-dd").parse(params?.workTime)
        }
        if (params?.currentWorkTime)
        {
            opportunity.contact.currentWorkTime = new SimpleDateFormat("yyyy-MM-dd").parse(params?.currentWorkTime)
        }
        if (opportunity.contact.validate())
        {
            opportunity.contact.save flush: true
        }
        else
        {
            println opportunity.contact.errors
        }

        redirect action: 'contactAssetInfo', id: opportunity?.id
    }

    def contactAssetInfo(Opportunity opportunity)
    {
        respond opportunity
    }

    @Transactional
    def contactAssetInfoSave(Opportunity opportunity)
    {
        if (opportunity.contact.validate())
        {
            opportunity.contact.save flush: true
        }
        else
        {
            println opportunity.contact.errors
        }

        redirect action: 'contactConnectPersonInfo', id: opportunity?.id
    }

    def contactConnectPersonInfo(Opportunity opportunity)
    {
        respond opportunity
    }

    @Transactional
    def contactConnectPersonInfoSave(Opportunity opportunity)
    {
        if (params?.fullName1 && params.opportunityContactType1)
        {
            def contact = new Contact()
            contact.fullName = params.fullName1
            contact.cellphone = params.cellphone1
            contact.companyName = params.companyName1
            if (contact.validate())
            {
                contact.save flush: true
            }
            else
            {
                println contact.errors
            }

            def opportunityContact = new OpportunityContact()
            opportunityContact.opportunity = opportunity
            opportunityContact.contact = contact
            opportunityContact.type = OpportunityContactType.findByName("联系人")
            opportunityContact.connectedContact = opportunity?.contact
            opportunityContact.connectedType = OpportunityContactType.findById(params.opportunityContactType1)
            if (opportunityContact.validate())
            {
                opportunityContact.save flush: true
            }
            else
            {
                println opportunityContact.errors
            }
        }

        if (params?.fullName2 && params.opportunityContactType2)
        {
            def contact = new Contact()
            contact.fullName = params.fullName2
            contact.cellphone = params.cellphone2
            contact.companyName = params.companyName2
            if (contact.validate())
            {
                contact.save flush: true
            }
            else
            {
                println contact.errors
            }

            def opportunityContact = new OpportunityContact()
            opportunityContact.opportunity = opportunity
            opportunityContact.contact = contact
            opportunityContact.type = OpportunityContactType.findByName("联系人")
            opportunityContact.connectedContact = opportunity?.contact
            opportunityContact.connectedType = OpportunityContactType.findById(params.opportunityContactType2)
            if (opportunityContact.validate())
            {
                opportunityContact.save flush: true
            }
            else
            {
                println opportunityContact.errors
            }
        }
        approveStage(opportunity)
    }

    // 汽车
    def createInterviewForm(Opportunity opportunity)
    {
        respond opportunity
    }

    //优客
    def createInterviewForm2(Opportunity opportunity)
    {
        respond opportunity
    }

    //车位
    def createInterviewForm3(Opportunity opportunity)
    {
        respond opportunity
    }

    //家装
    def createInterviewForm4(Opportunity opportunity)
    {
        respond opportunity
    }

    @Transactional
    def createInterviewFormSave(Opportunity opportunity)
    {
        params.vehicle.opportunity = opportunity
        def vehicle = new Vehicle(params?.vehicle)
        if (vehicle.validate())
        {
            vehicle.save flush: true
        }
        else
        {
            println vehicle?.errors
        }

        def numberOfAccount1 = params?.bankAccount1?.numberOfAccount
        if (numberOfAccount1)
        {
            def bankAccount1 = new BankAccount(params?.bankAccount1)
            if (bankAccount1.validate())
            {
                bankAccount1.save flush: true

                def contatBankAccount = new ContactBankAccount()
                contatBankAccount.contact = opportunity?.contact
                contatBankAccount.bankAccount = bankAccount1
                contatBankAccount.save flush: true
            }
            else
            {
                println bankAccount1.errors
            }
        }

        def bankAccount = new BankAccount(params?.bankAccount)
        if (bankAccount.validate())
        {
            if (bankAccount.validate())
            {
                bankAccount.save flush: true
            }
            else
            {
                println bankAccount.errors
            }

            def contatBankAccount = new ContactBankAccount()
            contatBankAccount.contact = opportunity?.contact
            contatBankAccount.bankAccount = bankAccount
            contatBankAccount.save flush: true
        }
        else
        {
            println bankAccount?.errors
        }

        def numberOfAccount3 = params?.bankAccount3?.numberOfAccount
        if (numberOfAccount3)
        {
            def bankAccount3 = new BankAccount(params?.bankAccount3)
            if (bankAccount3.validate())
            {
                bankAccount3.save flush: true

                def contatBankAccount = new ContactBankAccount()
                contatBankAccount.contact = opportunity?.contact
                contatBankAccount.bankAccount = bankAccount3
                contatBankAccount.save flush: true
            }
            else
            {
                println bankAccount3.errors
            }
        }

        // 厂商贴息费率
        def commissionRateTemp = params?.commissionRateTemp
        if (commissionRateTemp)
        {
            opportunity.commissionRate = commissionRateTemp?.toDouble() / 100
        }
        // 客户费率
        def monthlyInterestTemp = params?.monthlyInterestTemp
        if (monthlyInterestTemp)
        {
            opportunity.monthlyInterest = monthlyInterestTemp?.toDouble() / 100
        }
        opportunity.save flush: true

        approveStage(opportunity)
    }

    @Transactional
    def createInterviewForm2Save(Opportunity opportunity)
    {
        def numberOfAccount1 = params?.bankAccount1?.numberOfAccount
        if (numberOfAccount1)
        {
            def bankAccount1 = new BankAccount(params?.bankAccount1)
            if (bankAccount1.validate())
            {
                bankAccount1.save flush: true

                def contatBankAccount = new ContactBankAccount()
                contatBankAccount.contact = opportunity?.contact
                contatBankAccount.bankAccount = bankAccount1
                contatBankAccount.save flush: true
            }
            else
            {
                println bankAccount1.errors
            }
        }

        def bankAccount = new BankAccount(params?.bankAccount)
        if (bankAccount.validate())
        {
            if (bankAccount.validate())
            {
                bankAccount.save flush: true
            }
            else
            {
                println bankAccount.errors
            }

            def contatBankAccount = new ContactBankAccount()
            contatBankAccount.contact = opportunity?.contact
            contatBankAccount.bankAccount = bankAccount
            contatBankAccount.save flush: true
        }
        else
        {
            println bankAccount?.errors
        }

        def numberOfAccount2 = params?.bankAccount2?.numberOfAccount
        if (numberOfAccount2)
        {
            def bankAccount2 = new BankAccount(params?.bankAccount2)
            if (bankAccount2.validate())
            {
                bankAccount2.save flush: true
            }
            else
            {
                println bankAccount2.errors
            }

            def contatBankAccount = new ContactBankAccount()
            contatBankAccount.contact = opportunity?.contact
            contatBankAccount.bankAccount = bankAccount2
            contatBankAccount.save flush: true
        }

        def numberOfAccount3 = params?.bankAccount3?.numberOfAccount
        if (numberOfAccount3)
        {
            def bankAccount3 = new BankAccount(params?.bankAccount3)
            if (bankAccount3.validate())
            {
                bankAccount3.save flush: true

                def contatBankAccount = new ContactBankAccount()
                contatBankAccount.contact = opportunity?.contact
                contatBankAccount.bankAccount = bankAccount3
                contatBankAccount.save flush: true
            }
            else
            {
                println bankAccount3.errors
            }
        }

        // 厂商贴息费率
        def commissionRateTemp = params?.commissionRateTemp
        if (commissionRateTemp)
        {
            opportunity.commissionRate = commissionRateTemp?.toDouble() / 100
        }
        // 客户费率
        def monthlyInterestTemp = params?.monthlyInterestTemp
        if (monthlyInterestTemp)
        {
            opportunity.monthlyInterest = monthlyInterestTemp?.toDouble() / 100
        }
        opportunity.save flush: true

        approveStage(opportunity)
    }

    @Transactional
    def createInterviewForm3Save(Opportunity opportunity)
    {
        def numberOfAccount1 = params?.bankAccount1?.numberOfAccount
        if (numberOfAccount1)
        {
            def bankAccount1 = new BankAccount(params?.bankAccount1)
            if (bankAccount1.validate())
            {
                bankAccount1.save flush: true

                def contatBankAccount = new ContactBankAccount()
                contatBankAccount.contact = opportunity?.contact
                contatBankAccount.bankAccount = bankAccount1
                contatBankAccount.save flush: true
            }
            else
            {
                println bankAccount1.errors
            }
        }

        def bankAccount = new BankAccount(params?.bankAccount)
        if (bankAccount.validate())
        {
            if (bankAccount.validate())
            {
                bankAccount.save flush: true
            }
            else
            {
                println bankAccount.errors
            }

            def contatBankAccount = new ContactBankAccount()
            contatBankAccount.contact = opportunity?.contact
            contatBankAccount.bankAccount = bankAccount
            contatBankAccount.save flush: true
        }
        else
        {
            println bankAccount?.errors
        }

        def numberOfAccount3 = params?.bankAccount3?.numberOfAccount
        if (numberOfAccount3)
        {
            def bankAccount3 = new BankAccount(params?.bankAccount3)
            if (bankAccount3.validate())
            {
                bankAccount3.save flush: true

                def contatBankAccount = new ContactBankAccount()
                contatBankAccount.contact = opportunity?.contact
                contatBankAccount.bankAccount = bankAccount3
                contatBankAccount.save flush: true
            }
            else
            {
                println bankAccount3.errors
            }
        }

        // 厂商贴息费率
        def commissionRateTemp = params?.commissionRateTemp
        if (commissionRateTemp)
        {
            opportunity.commissionRate = commissionRateTemp?.toDouble() / 100
        }
        // 客户费率
        def monthlyInterestTemp = params?.monthlyInterestTemp
        if (monthlyInterestTemp)
        {
            opportunity.monthlyInterest = monthlyInterestTemp?.toDouble() / 100
        }
        opportunity.save flush: true

        approveStage(opportunity)
    }

    @Transactional
    def createInterviewForm4Save(Opportunity opportunity)
    {
        def house = new House(params?.house)
        house.opportunity = opportunity
        if (params?.purchaseDate)
        {
            house.purchaseDate = new SimpleDateFormat("yyyy-MM-dd").parse(params?.purchaseDate)
        }
        if (params?.decorationContractTime)
        {
            house.decorationContractTime = new SimpleDateFormat("yyyy-MM-dd").parse(params?.decorationContractTime)
        }
        if (params?.decorationTime)
        {
            house.decorationTime = new SimpleDateFormat("yyyy-MM-dd").parse(params?.decorationTime)
        }
        if (params?.houseDeliveryDate)
        {
            house.houseDeliveryDate = new SimpleDateFormat("yyyy-MM-dd").parse(params?.houseDeliveryDate)
        }
        if (house.validate())
        {
            house.save flush: true
        }
        else
        {
            println house?.errors
        }

        def numberOfAccount1 = params?.bankAccount1?.numberOfAccount
        if (numberOfAccount1)
        {
            def bankAccount1 = new BankAccount(params?.bankAccount1)
            if (bankAccount1.validate())
            {
                bankAccount1.save flush: true

                def contatBankAccount = new ContactBankAccount()
                contatBankAccount.contact = opportunity?.contact
                contatBankAccount.bankAccount = bankAccount1
                contatBankAccount.save flush: true
            }
            else
            {
                println bankAccount1.errors
            }
        }

        def bankAccount = new BankAccount(params?.bankAccount)
        if (bankAccount.validate())
        {
            if (bankAccount.validate())
            {
                bankAccount.save flush: true
            }
            else
            {
                println bankAccount.errors
            }

            def contatBankAccount = new ContactBankAccount()
            contatBankAccount.contact = opportunity?.contact
            contatBankAccount.bankAccount = bankAccount
            contatBankAccount.save flush: true
        }
        else
        {
            println bankAccount?.errors
        }

        def numberOfAccount3 = params?.bankAccount3?.numberOfAccount
        if (numberOfAccount3)
        {
            def bankAccount3 = new BankAccount(params?.bankAccount3)
            if (bankAccount3.validate())
            {
                bankAccount3.save flush: true

                def contatBankAccount = new ContactBankAccount()
                contatBankAccount.contact = opportunity?.contact
                contatBankAccount.bankAccount = bankAccount3
                contatBankAccount.save flush: true
            }
            else
            {
                println bankAccount3.errors
            }
        }
        
        // 厂商贴息费率
        def commissionRateTemp = params?.commissionRateTemp
        if (commissionRateTemp)
        {
            opportunity.commissionRate = commissionRateTemp?.toDouble() / 100
        }
        // 客户费率
        def monthlyInterestTemp = params?.monthlyInterestTemp
        if (monthlyInterestTemp)
        {
            opportunity.monthlyInterest = monthlyInterestTemp?.toDouble() / 100
        }
        opportunity.save flush: true

        approveStage(opportunity)
    }

    /** @Description 百融准入警示信息列表* @Params opportunity* @Return fields* @Author Nagelan* @DateTime 2019/1/11 0011 15:14
     */
    def warningDetail(Opportunity opportunity)
    {
        def opportunityFlexFieldCategory = com.next.OpportunityFlexFieldCategory.findByOpportunityAndFlexFieldCategory(opportunity, com.next.FlexFieldCategory.findByName("准入警示信息"))
        def fields = opportunityFlexFieldCategory?.fields
        if (fields)
        {
            respond opportunity, model: [fields: fields]
        }
        else
        {
            approveStage(opportunity)
        }
    }

    @Transactional
    def warningDetailSave(Opportunity opportunity)
    {
        def opportunityFlexFieldCategory = com.next.OpportunityFlexFieldCategory.findByOpportunityAndFlexFieldCategory(opportunity, com.next.FlexFieldCategory.findByName("准入警示信息"))
        def fields
        if (opportunityFlexFieldCategory)
        {
            fields = opportunityFlexFieldCategory.fields
            fields.each { OpportunityFlexField opportunityFlexField ->
                opportunityFlexField.value = params.get(opportunityFlexField.name)
                opportunityFlexField.save(flush: true)
            }
            println("警示原因保存成功")
        }
        approveStage(opportunity)
    }

    //收集材料核验
    def materialCheck(Opportunity opportunity)
    {
        def opportunityFlexFieldCategory = OpportunityFlexFieldCategory.findByOpportunityAndFlexFieldCategory(opportunity, FlexFieldCategory.findByName("材料核验"))
        respond opportunity, model: [opportunityFlexFieldCategory: opportunityFlexFieldCategory]
    }

    def materialCheckSave(Opportunity opportunity)
    {
        println params
        def opportunityFlexFieldCategoryId = params['opportunityFlexFieldCategoryId']
        def opportunityFlexFieldCategory = OpportunityFlexFieldCategory.findById(opportunityFlexFieldCategoryId)
        opportunityFlexFieldCategory?.fields?.each {
            if (params[it?.name])
            {
                it?.value = "是"
                it.save flush: true
            }
        }

        getMaterialCheckView(opportunity, params?.displayOrder)
    }

    def materialCheckMethod(Opportunity opportunity)
    {
        respond opportunity
    }

    @Transactional
    def materialCheckMethodSave(Opportunity opportunity)
    {
        opportunity.verifyMethod = params?.verifyMethod
        opportunity.save flush: true
        approveStage(opportunity)
    }

    //保单验证
    def materialPolicyValidation(Opportunity opportunity)
    {
        respond opportunity
    }

    @Transactional
    def materialPolicyValidationSave(Opportunity opportunity)
    {

        batchAttachmentInsert(opportunity, params?.attachmentUrl, "商业险保单")

        def vehicle = Vehicle.findByOpportunity(opportunity)
        if (!vehicle)
        {
            vehicle = new Vehicle()
            vehicle.opportunity = opportunity
        }

        vehicle.carframeCode = params?.carframeCode
        vehicle.commercialWarrantyCode = params?.commercialWarrantyCode
        vehicle.vehicleLossInsurance = params?.vehicleLossInsurance ? params?.vehicleLossInsurance?.toDouble() : 0
        vehicle.thirdDutyInsurance = params?.thirdDutyInsurance ? params?.thirdDutyInsurance?.toDouble() : 0
        vehicle.commercialWarranVerifyMethod = params?.commercialWarranVerifyMethod
        vehicle.save flush: true

        getMaterialCheckView(opportunity, params?.displayOrder)
    }

    //车辆发票验证
    def materialVehicleInvoiceVerification(Opportunity opportunity)
    {
        respond opportunity
    }

    @Transactional
    def materialVehicleInvoiceVerificationSave(Opportunity opportunity)
    {

        batchAttachmentInsert(opportunity, params?.attachmentUrl, "购车发票")

        def vehicle = Vehicle.findByOpportunity(opportunity)
        if (!vehicle)
        {
            vehicle = new Vehicle()
            vehicle.opportunity = opportunity
        }

        vehicle.purchaseTaxAmount = params?.purchaseTaxAmount ? params?.purchaseTaxAmount?.toDouble() : 0
        vehicle.purchaseInvoiceVerifyMethod = params?.purchaseInvoiceVerifyMethod
        vehicle.save flush: true

        getMaterialCheckView(opportunity, params?.displayOrder)
    }

    //房产验证
    def materialHouseVerification(Opportunity opportunity)
    {
        respond opportunity
    }

    @Transactional
    def materialHouseVerificationSave(Opportunity opportunity)
    {

        batchAttachmentInsert(opportunity, params?.attachmentUrl, "房产材料")

        getMaterialCheckView(opportunity, params?.displayOrder)
    }

    //个税验证
    def materialIncomeTaxValidation(Opportunity opportunity)
    {
        respond opportunity
    }

    @Transactional
    def materialIncomeTaxValidationSave(Opportunity opportunity)
    {

        batchAttachmentInsert(opportunity, params?.attachmentUrl, "缴税信息")

        getMaterialCheckView(opportunity, params?.displayOrder)
    }

    //公积金验证
    def materialAccumulationFundValidation(Opportunity opportunity)
    {
        respond opportunity
    }

    @Transactional
    def materialAccumulationFundValidationSave(Opportunity opportunity)
    {

        batchAttachmentInsert(opportunity, params?.accumulationFundInfoUrl, "公积金详情")
        batchAttachmentInsert(opportunity, params?.accumulationFundOrderUrl, "公积金流水")

        getMaterialCheckView(opportunity, params?.displayOrder)
    }

    //购置税完税证明验证
    def materialPurchaseTaxValidation(Opportunity opportunity)
    {
        respond opportunity
    }

    @Transactional
    def materialPurchaseTaxValidationSave(Opportunity opportunity)
    {

        batchAttachmentInsert(opportunity, params?.carInvoiceUrl, "购车发票")
        batchAttachmentInsert(opportunity, params?.purchaseTaxPayTaxesUrl, "购置税完税证明")

        def vehicle = Vehicle.findByOpportunity(opportunity)
        if (!vehicle)
        {
            vehicle = new Vehicle()
            vehicle.opportunity = opportunity
        }

        vehicle.purchaseTaxPayTaxesCode = params?.purchaseTaxPayTaxesCode
        vehicle.purchaseTaxPayTaxesAmount = params?.purchaseTaxPayTaxesAmount ? params?.purchaseTaxPayTaxesAmount?.toDouble() : 0
        vehicle.purchaseTaxPayTaxesVerifyMethod = params?.purchaseTaxPayTaxesVerifyMethod
        vehicle.save flush: true

        getMaterialCheckView(opportunity, params?.displayOrder)
    }

    //婚姻验证
    def materialMarriageValidation(Opportunity opportunity)
    {
        respond opportunity
    }

    @Transactional
    def materialMarriageValidationSave(Opportunity opportunity)
    {

        batchAttachmentInsert(opportunity, params?.attachmentUrl, "婚姻证明材料")

        getMaterialCheckView(opportunity, params?.displayOrder)
    }

    //家访验证
    def materialFamilyVisitValidation(Opportunity opportunity)
    {
        respond opportunity
    }

    //家访记录
    def familyVisitForm(Opportunity opportunity)
    {
    }

    @Transactional
    def materialFamilyVisitValidationSave(Opportunity opportunity)
    {

        batchAttachmentInsert(opportunity, params?.streetUrl, "街道照片-含街道名称")
        batchAttachmentInsert(opportunity, params?.communityUrl, "小区(社区)")
        batchAttachmentInsert(opportunity, params?.unitUrl, "单元门头")
        batchAttachmentInsert(opportunity, params?.houseDoorUrl, "房门头照")
        batchAttachmentInsert(opportunity, params?.parlorUrl, "客厅（办公室）")
        batchAttachmentInsert(opportunity, params?.kitchenUrl, "厨房（办公室）")

        getMaterialCheckView(opportunity, params?.displayOrder)
    }

    //驾照验证
    def materialDrivingLicenseVerification(Opportunity opportunity)
    {
        respond opportunity
    }

    @Transactional
    def materialDrivingLicenseVerificationSave(Opportunity opportunity)
    {

        batchAttachmentInsert(opportunity, params?.attachmentUrl, "驾照信息")
        getMaterialCheckView(opportunity, params?.displayOrder)
    }

    //流水验证
    def materialBillVerification(Opportunity opportunity)
    {
        respond opportunity
    }

    @Transactional
    def materialBillVerificationSave(Opportunity opportunity)
    {

        batchAttachmentInsert(opportunity, params?.attachmentUrl, "流水凭证")

        getMaterialCheckView(opportunity, params?.displayOrder)
    }

    //    营业执照验证
    def materialBusinessLicenseVerification(Opportunity opportunity)
    {
        respond opportunity
    }

    @Transactional
    def materialBusinessLicenseVerificationSave(Opportunity opportunity)
    {
        batchAttachmentInsert(opportunity, params?.attachmentUrl, "营业执照信息")

        getMaterialCheckView(opportunity, params?.displayOrder)
    }

    //    社保验证
    def materialSocialSecurityVerification(Opportunity opportunity)
    {
        respond opportunity
    }

    @Transactional
    def materialSocialSecurityVerificationSave(Opportunity opportunity)
    {

        batchAttachmentInsert(opportunity, params?.socialSecurityInfoUrl, "社保详情")
        batchAttachmentInsert(opportunity, params?.socialSecurityOrderUrl, "社保流水")

        getMaterialCheckView(opportunity, params?.displayOrder)
    }

    //   学历验证
    def materialEducationVerification(Opportunity opportunity)
    {
        respond opportunity
    }

    @Transactional
    def materialEducationVerificationSave(Opportunity opportunity)
    {

        batchAttachmentInsert(opportunity, params?.attachmentUrl, "学历信息")
        getMaterialCheckView(opportunity, params?.displayOrder)
    }

    //用途验证
    def materialUseVerification(Opportunity opportunity)
    {
        respond opportunity
    }

    @Transactional
    def materialUseVerificationSave(Opportunity opportunity)
    {

        batchAttachmentInsert(opportunity, params?.attachmentUrl, "用途信息")

        getMaterialCheckView(opportunity, params?.displayOrder)
    }

    //现场验证拍照-划付授权书
    def paymentAuthorization(Opportunity opportunity)
    {
        respond opportunity
    }

    @Transactional
    def paymentAuthorizationSave(Opportunity opportunity)
    {
        batchAttachmentInsert(opportunity, params?.attachmentUrl, "划付授权书")

        redirect action: 'stagingBusinessContract', id: opportunity?.id
    }

    //分期业务合同
    def stagingBusinessContract(Opportunity opportunity)
    {
        respond opportunity
    }

    @Transactional
    def stagingBusinessContractSave(Opportunity opportunity)
    {

        batchAttachmentInsert(opportunity, params?.attachmentUrl, "分期业务合同协议")

        redirect action: 'stagingBusinessInform', id: opportunity?.id
    }

    //分期业务告知书
    def stagingBusinessInform(Opportunity opportunity)
    {
        respond opportunity
    }

    @Transactional
    def stagingBusinessInformSave(Opportunity opportunity)
    {
        // 上传材料
        batchAttachmentInsert(opportunity, params?.attachmentUrl, "分期业务告知书")

        approveStage(opportunity)
    }

    //    授权书协议
    def certificateAuthorization()
    {
    }

    def certificateAuthorization1()
    {
    }

    /** @Description 页面执行组件* @Params map* @Return json* @Author Nagelan* @DateTime 2018/12/28 0028 11:06
     */
    @Secured('permitAll')
    def ajaxEvaluateComponent()
    {
        println "params:" + params
        def data = params
        def component = Component.findByName(params.component)
        if (component && data)
        {
            def result = componentService.evaluate(component, data)
            render(result as JSON)
        }
        else
        {
            render(["code": "100", "msg": "没有找到组件"] as JSON)
        }
        return null
    }

    /** @Description 安心签调用组件* @Params map* @Return json* @Author Nagelan* @DateTime 2019/1/16 0016 11:08
     */
    @Secured('permitAll')
    def anxinqianEvaluateComponent()
    {
        def data = params
        data.jksPath = servletContext.getRealPath("/") + "axqjks/anxinsign.jks"
        println "params:" + data
        def component = Component.findByName(params.component)
        if (component && data)
        {
            def result = componentService.evaluate(component, data)
            def email = Opportunity.findById(data.opportunityId)?.contact?.email
            if (params.type == "download" && result && email)
            {
                mailService.sendMail {
                    multipart(true)
                    to "${email}"
                    subject "合同附件"
                    text "请下载您的合同附件"
                    attach "合同附件.zip", "application/zip", result
                }
                println("发送成功")
            }
            render(result)
        }
        else
        {
            render(["code": "100", "msg": "没有找到组件"] as JSON)
        }
        return null
    }

    //面签app订单列表接口
    def appOpportunityList(Opportunity opportunity)
    {
        def code = "200"
        def data
        def message = "返回成功"
        if (opportunity)
        {
            def user = opportunity.user
            data = Opportunity.executeQuery("select new map(o.serialNumber as serialNumber,o.fullName as fullName ,o.cellphone as cellphone,o.idNumber as idNumber,o.id as id,o.interviewResult as interviewResult) from Opportunity o  where o.user.id=${user.id} order by o.createdDate desc")
            //todo 获取面签状态
            if (data && data.size() > 0)
            {
                data.each {
                    if (it?.interviewResult && it?.interviewResult == '通过')
                    {
                        it.status = '1'
                    }
                    else
                    {
                        it.status = '0'
                    }

                }
            }
            code = "200"
            message = "返回成功"
        }
        else
        {
            code = "400"
            message = "无订单信息"
        }

        def map = [code: code, message: message, data: data]
        render(map as JSON)
    }

    //面签app订单信息
    def appOpportunity(Opportunity opportunity)
    {
        def code = 200
        def message = "返回成功"
        def data = new ArrayList()

        if (opportunity)
        {
            //身份证信息
            def map = new HashMap()
            def picMap = new HashMap()
            picMap.img1 = Attachments.findByOpportunityAndType(opportunity, AttachmentType.findByName("借款人身份证正面"))?.fileUrl
            picMap.img2 = Attachments.findByOpportunityAndType(opportunity, AttachmentType.findByName("借款人身份证反面"))?.fileUrl

            map.key = "客户证件信息"
            map.values = picMap
            data.add(map)
            //客户信息
            def clientMap = new HashMap<Object, Object>()
            clientMap.key = "客户信息"
            def clientList = new ArrayList<Object>()
            clientList.add([title: "客户姓名", detail: opportunity?.fullName])
            clientList.add([title: "身份证号", detail: opportunity?.idNumber])
            clientMap.values = clientList
            data.add(clientMap)

            //客户申请信息
            def clientAppliMap = new HashMap<Object, Object>()
            clientAppliMap.key = "客户申请信息"
            def clientApplList = new ArrayList<Object>()
            clientApplList.add([title: "商品品牌", detail: opportunity?.brand])
            clientApplList.add([title: "型号", detail: opportunity?.marque])
            clientApplList.add([title: "商品总价", detail: opportunity?.loanAmount ? opportunity?.loanAmount.toString() : '-'])
            clientApplList.add([title: "申请金额", detail: opportunity?.requestedAmount ? opportunity?.requestedAmount.toString() : '-'])
            clientApplList.add([title: "申请期数", detail: opportunity?.loanDuration + "期"])
            clientAppliMap.values = clientApplList
            data.add(clientAppliMap)

        }
        else
        {
            code = 400
            message = "返回失败,订单不存在"
        }
        render([code: code, message: message, data: data] as JSON)

    }

    private static
    final char[] HEX_DIGITS = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']

    def encode(String algorithm, String value)
    {
        if (value == null)
        {
            return null
        }
        try
        {
            MessageDigest messageDigest = MessageDigest.getInstance(algorithm)
            messageDigest.update(value.getBytes())
            return getFormattedText(messageDigest.digest())
        }
        catch (Exception e)
        {
            throw new RuntimeException(e)
        }
    }

    def getFormattedText(def bytes)
    {
        int len = bytes.length
        StringBuilder buf = new StringBuilder(len * 2)
        for (
            int j = 0;
                j < len;
                j++)
        {
            buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f])
            buf.append(HEX_DIGITS[bytes[j] & 0x0f])
        }
        return buf.toString()
    }

    def getCheckSum(String appSecret, String nonce, String curTime)
    {
        return encode("sha1", appSecret + nonce + curTime)
    }

    def getMD5(String requestBody)
    {
        return encode("md5", requestBody)
    }

    /** @Description app注册云信用户获取token app用户使用
     * @Params map* @Return json* @Author Nagelan* @DateTime 2019/1/2 0002 16:47
     */
    @Secured('permitAll')
    def getYunxinToken()
    {
        // 修改为订单号作为accid
        def opportunity = Opportunity.findById(Long.parseLong(params?.opportunityId))
        def result = []
        if (opportunity?.yxToken)
        {
            result = [code: 200, info: [token: opportunity?.yxToken, accid: opportunity?.serialNumber, name: opportunity?.fullName, linkAccid: "17610867397"]] as JSON
        }
        else
        {
            def url = new java.net.URL("https://api.netease.im/nimserver/user/create.action")
            def requestData
            def appKey = "b11092a625ee18f79f18479eac4ad862"
            def nonce = "12345678"
            def appSecret = "5f4b3836bded"
            def curTime = (new Date().time / 1000).intValue().toString()
            def checkSum = getCheckSum(appSecret, nonce, curTime)
            requestData = "accid=${opportunity?.serialNumber}&name=${opportunity?.fullName}"
            try
            {
                def connection = (java.net.HttpURLConnection) url.openConnection()
                connection.setDoOutput(true)
                connection.setRequestMethod("POST")
                connection.setRequestProperty("AppKey", appKey)
                connection.setRequestProperty("Nonce", nonce)
                connection.setRequestProperty("CurTime", curTime)
                connection.setRequestProperty("CheckSum", checkSum)
                connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=utf-8")
                connection.outputStream.withWriter("UTF-8") { java.io.Writer writer -> writer.write requestData }
                connection.setConnectTimeout(10000)
                def r = connection.inputStream.withReader("UTF-8") { java.io.Reader reader -> reader.text }
                result = grails.converters.JSON.parse(r)
                println(result)
                if (result.code == 200)
                {
                    result.linkAccid = "17610867397"
                    opportunity.yxToken = result.info.token
                    opportunity.save flush: true
                }
                else
                {
                    println("请求token失败")
                    result = refreshToken(opportunity)

                }
            }
            catch (java.lang.Exception e)
            {
                e.printStackTrace()
                println(e)
            }
        }
        render(result)
        return null
    }

    def refreshToken(Opportunity opportunity)
    {
        def result
        def url = new java.net.URL("https://api.netease.im/nimserver/user/refreshToken.action")
        def requestData
        def appKey = "b11092a625ee18f79f18479eac4ad862"
        def nonce = "12345678"
        def appSecret = "5f4b3836bded"
        def curTime = (new Date().time / 1000).intValue().toString()
        def checkSum = getCheckSum(appSecret, nonce, curTime)
        requestData = "accid=${opportunity?.serialNumber}&name=${opportunity?.fullName}"
        try
        {
            def connection = (java.net.HttpURLConnection) url.openConnection()
            connection.setDoOutput(true)
            connection.setRequestMethod("POST")
            connection.setRequestProperty("AppKey", appKey)
            connection.setRequestProperty("Nonce", nonce)
            connection.setRequestProperty("CurTime", curTime)
            connection.setRequestProperty("CheckSum", checkSum)
            connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=utf-8")
            connection.outputStream.withWriter("UTF-8") { java.io.Writer writer -> writer.write requestData }
            connection.setConnectTimeout(10000)
            def r = connection.inputStream.withReader("UTF-8") { java.io.Reader reader -> reader.text }
            result = grails.converters.JSON.parse(r)
            println(result)
            if (result.code == 200)
            {
                opportunity.yxToken = result.info.token
                opportunity.save flush: true
            }
            else
            {
                println("请求token失败")
            }
        }
        catch (java.lang.Exception e)
        {
            e.printStackTrace()
            println(e)
        }
        return result
    }

    def base()
    {
        new BASE64Encoder().encode()
    }

    def getContactFeatureByCategoryId()
    {
        def category = params["category"]
        if (!category || category == '-1' || category == 'null')
        {
            return ''
        }
        else
        {
            category = Long.parseLong(category)
            render([contactFeatureList: ContactFeature.executeQuery("select a.id as id, a.name as name from ContactFeature a where a.category.id = ${category}")] as JSON)
        }
    }

    def getLinkaccid()
    {
        // 获取要通信对象的accid
        def opportunity = Opportunity.findById(Long.parseLong(params?.opportunityId))
        def account = opportunity.user.account
        def users = User.executeQuery("select new map(u.cellphone as cellphone) from User u where u.account.id=${account?.id} and u.yxConnectedStatus='online' and  current_timestamp()< u.yxConnectedDate+numtodsinterval(30,'second') ").asList()
        if (users && users.size() > 0)
        {
            Random random = new Random()
            int n = random.nextInt(users.size())
            def user = users.get(n)
            render([code: 200, linkAccid: user?.cellphone] as JSON)
            return
        }
        else
        {
            render([code: 400, linkAccid: null] as JSON)
        }

    }

    /** @Description 获取百融测算返回列表* @Params opportunity* @Return fields* @Author Nagelan* @DateTime 2019/1/11 0011 14:17
     */
    def successfulList(Opportunity opportunity)
    {
        def result = componentService.evaluate(Component.findByName("百融额度测算"), opportunity)
        println "百融额度测算结果：" + result

        def opportunityFlexFieldCategory = OpportunityFlexFieldCategory.findByOpportunityAndFlexFieldCategory(opportunity, FlexFieldCategory.findByName("额度测算结果"))
        def fields
        if (opportunityFlexFieldCategory)
        {
            fields = opportunityFlexFieldCategory.fields
        }
        respond opportunity, model: [fields: fields]
    }

    /** @Description 安心签个人开户3001* @Params map* @Return json* @Author Nagelan* @DateTime 2019/1/7 0007 10:03
     */
    def anxinqian3001 = { dataMap ->
        def JKS_PATH = dataMap.jksPath
        def JKS_PWD = "wc167xd"
        def ALIAS = "anxinsign"
        def PLAT_ID = "7EF27857582F4FD8E05312016B0A5DC1"
        def opportunity = com.next.Opportunity.findById(dataMap.opportunityId)
        String txCode = "3001"
        cfca.trustsign.demo.connector.HttpConnector httpConnector = new cfca.trustsign.demo.connector.HttpConnector()
        httpConnector.init(JKS_PATH, JKS_PWD)

        cfca.trustsign.common.vo.request.tx3.Tx3001ReqVO tx3001ReqVO = new cfca.trustsign.common.vo.request.tx3.Tx3001ReqVO()
        cfca.trustsign.common.vo.cs.HeadVO head = new cfca.trustsign.common.vo.cs.HeadVO()
        head.setTxTime(new java.util.Date().format("yyyyMMddHHmmss"))

        cfca.trustsign.common.vo.cs.PersonVO person = new cfca.trustsign.common.vo.cs.PersonVO()
        person.setPersonName(opportunity?.contact?.fullName)
        person.setIdentTypeCode("0")
        person.setIdentNo(opportunity?.contact?.idNumber)
        person.setMobilePhone(opportunity?.contact?.cellphone)
        person.setAddress("北京")
        person.setAuthenticationMode("公安部")
        tx3001ReqVO.setHead(head)
        tx3001ReqVO.setPerson(person)

        // 身份认证时需要
        tx3001ReqVO.setIsVerifyBankCard(0)
        cfca.trustsign.common.vo.BankCardInfoVO bankCardInfo = new cfca.trustsign.common.vo.BankCardInfoVO()
        bankCardInfo.setPanNo("6225365271562822")
        bankCardInfo.setMobilePhone("13542314551")
        tx3001ReqVO.setBankCardInfo(bankCardInfo)
        // tx3001ReqVO.setSealColor(1);

        String req = new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(tx3001ReqVO)
        String signature = cfca.trustsign.demo.connector.SecurityUtil.p7SignMessageDetach(JKS_PATH, JKS_PWD, ALIAS, req)
        String res = httpConnector.post("platId/" + PLAT_ID + "/txCode/" + txCode + "/transaction", req, signature)
        println("res:" + res)
        return grails.converters.JSON.parse(res)
    }

    /** @Description 安心签企业开户 3002
     * @Params map* @Return json* @Author Nagelan* @DateTime 2019/1/7 0007 10:03
     */
    def anxinqian3002 = { dataMap ->
        def JKS_PATH = servletContext.getRealPath("/") + "axqjks/anxinsign.jks"
        def JKS_PWD = "wc167xd"
        def ALIAS = "anxinsign"
        def PLAT_ID = "7EF27857582F4FD8E05312016B0A5DC1"
        cfca.trustsign.demo.connector.HttpConnector httpConnector = new cfca.trustsign.demo.connector.HttpConnector()
        httpConnector.init(JKS_PATH, JKS_PWD)

        cfca.trustsign.common.vo.request.tx3.Tx3002ReqVO tx3002ReqVO = new cfca.trustsign.common.vo.request.tx3.Tx3002ReqVO()
        cfca.trustsign.common.vo.cs.HeadVO head = new cfca.trustsign.common.vo.cs.HeadVO()
        head.setTxTime(new java.util.Date().format("yyyyMMddHHmmss"))

        cfca.trustsign.common.vo.cs.EnterpriseVO enterprise = new cfca.trustsign.common.vo.cs.EnterpriseVO()
        enterprise.setEnterpriseName("北京国信达数据技术有限公司")
        enterprise.setIdentTypeCode("8")
        enterprise.setIdentNo("1100000179095628")
        enterprise.setMobilePhone("17610060356")
        enterprise.setLandlinePhone("69226906")
        //enterprise.setEmail("11900129@cfca.com.cn")
        enterprise.setAuthenticationMode("公安部")

        cfca.trustsign.common.vo.cs.EnterpriseTransactorVO enterpriseTransactor = new cfca.trustsign.common.vo.cs.EnterpriseTransactorVO()
        enterpriseTransactor.setTransactorName("王超")
        enterpriseTransactor.setIdentTypeCode("1")
        enterpriseTransactor.setIdentNo("140511199205111213")
        // enterpriseTransactor.setAddress("beijing")
        tx3002ReqVO.setHead(head)
        tx3002ReqVO.setEnterprise(enterprise)
        tx3002ReqVO.setEnterpriseTransactor(enterpriseTransactor)
        // tx3002ReqVO.setSealColor(2)
        String req = new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(tx3002ReqVO)
        String txCode = "3002"
        String signature = cfca.trustsign.demo.connector.SecurityUtil.p7SignMessageDetach(JKS_PATH, JKS_PWD, ALIAS, req)
        String res = httpConnector.post("platId/" + PLAT_ID + "/txCode/" + txCode + "/transaction", req, signature)
        println("res:" + res)
        def json = grails.converters.JSON.parse(res)
        if (json?.enterprise?.userId)
        {
            def category = com.next.FlexFieldCategory.findByName("安心签企业认证账户")
            if (!category)
            {
                category = new com.next.FlexFieldCategory(name: "安心签企业认证账户").save(flush: true)
            }
            def flexField = com.next.FlexField.findByNameAndCategory("安心签企业userId", category)
            if (!flexField)
            {
                flexField = new com.next.FlexField(name: "安心签企业userId", category: category, description: "安心签企业userId", dataType: "String", displayOrder: 1)
            }
            flexField.defaultValue = json?.enterprise?.userId
            flexField.save(flush: true)
            println("安心签userId保存成功success")
        }
        else
        {
            println("安心签userId保存失败failure")
        }
        return json
    }

    /** @Description 安心签创建合同  3201
     * @Params params* @Return json* @Author Nagelan* @DateTime 2019/1/14 0014 15:05
     */
    def anxinqian3201 = { dataMap ->
        def JKS_PATH = dataMap?.jksPath
        def JKS_PWD = "wc167xd"
        def ALIAS = "anxinsign"
        def PLAT_ID = "7EF27857582F4FD8E05312016B0A5DC1"
        def opportunity = com.next.Opportunity.findById(dataMap.opportunityId)
        def contractType = dataMap.contractType
        def result
        def userId = com.next.FlexField.findByNameAndCategory("安心签企业userId", com.next.FlexFieldCategory.findByName("安心签企业认证账户"))?.defaultValue
        if (opportunity?.product?.name && userId && contractType)
        {
            def product = opportunity?.product?.name
            def contractTemplate
            def template = ""
            if (contractType == "征信授权书" || contractType == "配偶征信授权书")
            {
                template = "征信授权书"
            }
            else
            {
                template = opportunity?.product?.name
            }
            contractTemplate = com.next.FlexField.findByNameAndCategory(template, com.next.FlexFieldCategory.findByName("合同模板"))
            if (contractTemplate?.defaultValue)
            {
                cfca.trustsign.demo.connector.HttpConnector httpConnector = new cfca.trustsign.demo.connector.HttpConnector()
                httpConnector.init(JKS_PATH, JKS_PWD)
                cfca.trustsign.common.vo.request.tx3.Tx3201ReqVO tx3201ReqVO = new cfca.trustsign.common.vo.request.tx3.Tx3201ReqVO()
                cfca.trustsign.common.vo.cs.HeadVO head = new cfca.trustsign.common.vo.cs.HeadVO()
                head.setTxTime(new java.util.Date().format("yyyyMMddHHmmss"))
                Map<String, String> fieldMap = new HashMap<String, String>()
                cfca.trustsign.common.vo.cs.CreateContractVO createContract = new cfca.trustsign.common.vo.cs.CreateContractVO()
                createContract.setIsSign(0)
                createContract.setTemplateId(contractTemplate?.defaultValue)
                createContract.setContractName(opportunity?.serialNumber)
                //createContract.setSignLocation("Signature1")

                def contact = opportunity?.contact
                def now = new java.util.Date()
                if (contractType == "征信授权书")
                {
                    fieldMap.put("1", "/")
                    fieldMap.put("2", "/") //曾用名
                    fieldMap.put("3", contact?.cellphone) //名
                    fieldMap.put("4", "/")
                    fieldMap.put("5", contact?.idNumber)
                    fieldMap.put("6", now?.format("yyyy"))
                    fieldMap.put("7", now?.format("MM"))
                    fieldMap.put("8", now?.format("dd"))
                }
                else if (contractType == "配偶征信授权书")
                {
                    contact = com.next.OpportunityContact.findByOpportunityAndType(opportunity, com.next.OpportunityContactType.findByName('借款人配偶'))?.contact
                    fieldMap.put("1", "/")
                    fieldMap.put("2", "/") //曾用名
                    fieldMap.put("3", contact?.cellphone) //名
                    fieldMap.put("4", "/")
                    fieldMap.put("5", contact?.idNumber)
                    fieldMap.put("6", now?.format("yyyy"))
                    fieldMap.put("7", now?.format("MM"))
                    fieldMap.put("8", now?.format("dd"))
                }
                else if (contractType == "业务申请表")
                {
                    //公共基础信息
                    //借款人信息
                    fieldMap.put("1", contact?.fullName)
                    fieldMap.put("2", contact?.lastName) //姓
                    fieldMap.put("3", contact?.firstName) //名
                    fieldMap.put("4", contact?.lastNameSpell) //姓拼音
                    fieldMap.put("5", contact?.firstNameSpell) //名拼音
                    fieldMap.put("6", contact?.gender)
                    fieldMap.put("7", contact?.birthday?.format("yyyyMMdd"))
                    fieldMap.put("8", contact?.maritalStatus)
                    fieldMap.put("9", contact?.cellphone)
                    fieldMap.put("10", contact?.identityType?.name)
                    fieldMap.put("11", contact?.idNumber)
                    fieldMap.put("12", contact?.periodOfValidity) //证件到期日
                    fieldMap.put("13", contact?.nativePlace)
                    fieldMap.put("14", contact?.authority) //户籍所在地
                    fieldMap.put("15", contact?.certificate?.name)
                    fieldMap.put("16", contact?.highestCertificate?.name)
                    fieldMap.put("17", opportunity?.houses[0]?.address ?: "/")
                    fieldMap.put("18", "")
                    fieldMap.put("19", "")
                    fieldMap.put("20", "")
                    if (contact?.housingFundPersonalAmount)
                    {
                        fieldMap.put("18", "是")
                        fieldMap.put("19", contact?.housingFundPersonalRatio + "")
                        fieldMap.put("20", contact?.housingFundPersonalAmount + "")
                    }
                    else if (contact?.socialInsurancePersonalAmount)
                    {
                        fieldMap.put("18", "是")
                        fieldMap.put("19", contact?.socialInsurancePersonalRatio + "")
                        fieldMap.put("20", contact?.socialInsurancePersonalAmount + "")
                    }
                    else if (contact?.individualIncomeTaxPersonalAmount)
                    {
                        fieldMap.put("18", "是")
                        fieldMap.put("19", contact?.individualIncomeTaxPersonalRatio + "")
                        fieldMap.put("20", contact?.individualIncomeTaxPersonalAmount + "")
                    }
                    fieldMap.put("21", contact?.address)
                    fieldMap.put("22", contact?.zipCode)
                    fieldMap.put("23", contact?.houseOrigin?.name)
                    fieldMap.put("24", contact?.residentialDuration)
                    //职业信息
                    fieldMap.put("25", contact?.companyName)
                    fieldMap.put("26", contact?.companyPhone)
                    fieldMap.put("27", contact?.companyAddress)
                    fieldMap.put("28", contact?.companyZipCode)
                    fieldMap.put("29", contact?.companyEconomyType?.name)
                    fieldMap.put("30", contact?.profession?.name)
                    fieldMap.put("31", contact?.professionTile?.name)
                    fieldMap.put("32", contact?.contactJob?.name)
                    fieldMap.put("33", contact?.workTime?.format("yyyyMMdd"))
                    fieldMap.put("34", contact?.currentWorkTime?.format("yyyyMMdd"))
                    //资产负债信息
                    fieldMap.put("35", contact?.monthlyIncome + "")
                    fieldMap.put("36", contact?.monthlyIncomeType)
                    fieldMap.put("37", contact?.monthlyIncomeVerifyMethod)
                    fieldMap.put("38", contact?.otherMembersMonthlyIncome + "")
                    fieldMap.put("39", "") //家庭其他成员月收入类型
                    fieldMap.put("40", contact?.otherMembersMonthlyIncomeVerifyMethod)
                    fieldMap.put("41", contact?.monthlyTotalIncome ? contact?.monthlyTotalIncome + "" : "/") //家庭总收入
                    fieldMap.put("42", contact?.familyMembersCount + "")
                    fieldMap.put("43", contact?.fendCount + "")
                    fieldMap.put("44", contact?.beCustomerDuration)
                    fieldMap.put("45", contact?.cardCountRange)
                    fieldMap.put("46", contact?.bankDealings)
                    fieldMap.put("47", contact?.houseType?.name)
                    //联系人信息
                    def oc = com.next.OpportunityContact.findAllByOpportunity(opportunity)

                    if (oc.size() > 0)
                    {
                        fieldMap.put("48", oc[0]?.contact?.fullName)
                        fieldMap.put("49", oc[0]?.connectedType?.name ?: "/")
                        fieldMap.put("50", oc[0]?.contact?.cellphone)
                        fieldMap.put("79", oc[0]?.contact?.companyName)
                        fieldMap.put("51", oc[1]?.contact?.fullName)
                        fieldMap.put("52", oc[1]?.connectedType?.name)
                        fieldMap.put("53", oc[1]?.contact?.cellphone)
                        fieldMap.put("54", oc[1]?.contact?.companyName)
                    }
                    def bankAccount = com.next.BankAccount.executeQuery("select c.bankAccount from ContactBankAccount c where c.contact.id = ${opportunity?.contact?.id} and c.bankAccount.type.name = '信用卡'")[0]
                    def bankAccount1 = com.next.BankAccount.executeQuery("select c.bankAccount from ContactBankAccount c where c.contact.id = ${opportunity?.contact?.id} and c.bankAccount.type.name = '借记卡'")[0]
                    def bankAccount2 = com.next.BankAccount.executeQuery("select c.bankAccount from ContactBankAccount c where c.contact.id = ${opportunity?.contact?.id} and c.bankAccount.type.name = '借记卡'")[1]
                    //信用卡产品信息
                    fieldMap.put("55", bankAccount?.numberOfAccount ?: "/")
                    fieldMap.put("56", bankAccount?.postAddressType ?: "/")
                    fieldMap.put("57", bankAccount?.billSentMethod ?: "/")
                    fieldMap.put("58", bankAccount?.creditCardPayMethod ?: "/")
                    fieldMap.put("59", bankAccount?.creditCardPaymentMethod ?: "/")
                    fieldMap.put("60", bankAccount?.creditCardPaymentType ?: "/")
                    fieldMap.put("61", bankAccount?.creditCardPaymentAccount ?: "/")
                    fieldMap.put("62", bankAccount1?.province?.name ?: "/") //开户行所在省市
                    fieldMap.put("63", bankAccount1?.numberOfAccount ?: "/") //人民币账号
                    fieldMap.put("64", bankAccount?.houseProperty ?: "/")
                    fieldMap.put("65", bankAccount?.wannaToIncreaseQuota ? "是" : "否")
                    fieldMap.put("66", bankAccount?.subType?.name ?: "/")
                    fieldMap.put("67", bankAccount?.code ?: "/")
                    fieldMap.put("68", bankAccount?.name ?: "/")
                    fieldMap.put("69", bankAccount?.circulationQuota ?: "/")
                    fieldMap.put("70", bankAccount?.connectmanIsClientManager ? "是" : "否")
                    fieldMap.put("71", bankAccount?.branchCode ?: "/")
                    fieldMap.put("72", bankAccount?.marketerCode ?: "/")
                    fieldMap.put("73", bankAccount?.marketingCampaignCode ?: "/") //CC
                    fieldMap.put("74", "/") //PN
                    fieldMap.put("75", "/") //EX
                    fieldMap.put("76", bankAccount?.noAnnualFeeType ?: "/")
                    fieldMap.put("77", bankAccount?.surnameOfMother ?: "/")
                    fieldMap.put("78", opportunity?.houses[0]?.area + "")
                    //公共申请分期类型
                    fieldMap.put("101", opportunity?.paymentMode ?: "/")
                    fieldMap.put("102", opportunity?.repaymentPeriod + "")
                    fieldMap.put("103", opportunity?.requestedAmount + "")
                    fieldMap.put("104", opportunity?.ompositeMonthlyInterest + "")
                    fieldMap.put("105", opportunity?.commissionPaymentMethod?.name ?: "/")
                    fieldMap.put("106", opportunity?.loanDuration + "")
                    fieldMap.put("107", opportunity?.commission + "")
                    fieldMap.put("108", opportunity?.principalPaymentMethod?.name ?: "/")
                    fieldMap.put("109", opportunity?.account?.name ?: "/")
                    //判断产品
                    if (product == "汽车分期")
                    {
                        fieldMap.put("124", opportunity?.vehicles[0]?.vehicleBrand ?: "/")
                        fieldMap.put("125", opportunity?.vehicles[0]?.vehicleSeries ?: "/")
                    }
                    else if (product == "家装分期")
                    {
                        fieldMap.put("110", opportunity?.paymentFrequency)
                        fieldMap.put("111", opportunity?.houses[0]?.decorationContractTime?.format("yyyyMMdd"))
                        fieldMap.put("112", opportunity?.houses[0]?.decorationTime?.format("yyyyMMdd"))
                        fieldMap.put("113", opportunity?.houses[0]?.decorationMethod)
                        fieldMap.put("114", opportunity?.houses[0]?.decorationTotalPrice + "")
                        fieldMap.put("115", opportunity?.houses[0]?.decorationUnitprice + "")
                        fieldMap.put("116", opportunity?.houses[0]?.decorationArea + "")
                        fieldMap.put("117", opportunity?.houses[0]?.address ?: "/")
                        fieldMap.put("118", opportunity?.houses[0]?.houseProperty ?: "/")
                        fieldMap.put("119", opportunity?.houses[0]?.purchaseAmount + "")
                        fieldMap.put("120", opportunity?.houses[0]?.purchaseDate?.format("yyyyMMdd"))
                        fieldMap.put("121", opportunity?.houses[0]?.houseSubType)
                        fieldMap.put("122", opportunity?.houses[0]?.purchaseArea + "")
                        fieldMap.put("123", opportunity?.houses[0]?.houseDeliveryDate?.format("yyyyMMdd"))
                    }
                    else if (product == "客群分期")
                    {
                        fieldMap.put("126", opportunity?.loanUsage ?: "/")
                        fieldMap.put("127", opportunity?.minInstallmentAmount ? opportunity?.minInstallmentAmount + "" : "/")
                        fieldMap.put("128", "")
                        if (bankAccount2)
                        {
                            fieldMap.put("128", bankAccount2?.numberOfAccount ?: "/")
                        }
                        else if (bankAccount1)
                        {
                            fieldMap.put("128", bankAccount1?.numberOfAccount ?: "/")
                        }
                    }
                    else if (product == "车位分期")
                    {
                        //暂无
                    }
                }

                createContract.setTextValueInfo(fieldMap)
                createContract.setIsSaveTextValue(1)

                cfca.trustsign.common.vo.cs.SignInfoVO[] signInfos = new cfca.trustsign.common.vo.cs.SignInfoVO[1]
                cfca.trustsign.common.vo.cs.SignInfoVO signInfoVO0 = new cfca.trustsign.common.vo.cs.SignInfoVO()
                signInfoVO0.setUserId(userId)
                signInfoVO0.setIsProxySign(0)
                signInfoVO0.setLocation("211.94.108.226")
                signInfoVO0.setProjectCode("0")
                signInfoVO0.setSignLocation("Signature1")
                signInfoVO0.setAuthorizationTime(now.format("yyyyMMddHHmmss"))
                signInfos[0] = signInfoVO0
                cfca.trustsign.common.vo.cs.SignInfoVO signInfoVO1 = new cfca.trustsign.common.vo.cs.SignInfoVO()
                //userId   96428FD7E441461DA91C797EC0B02CED
                /*signInfoVO1.setUserId("96428FD7E441461DA91C797EC0B02CED")
                signInfoVO1.setIsProxySign(0)
                signInfoVO1.setLocation("211.94.108.226")
                signInfoVO1.setProjectCode("0")
                signInfoVO1.setSignLocation("Signature2")
                signInfoVO1.setAuthorizationTime(now.format("yyyyMMddHHmmss"))
                signInfos[1] = signInfoVO1*/
                createContract.setSignInfos(signInfos)

                tx3201ReqVO.setHead(head)
                tx3201ReqVO.setCreateContract(createContract)

                String req = new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(tx3201ReqVO)

                String txCode = "3201"
                String signature = cfca.trustsign.demo.connector.SecurityUtil.p7SignMessageDetach(JKS_PATH, JKS_PWD, ALIAS, req)
                String res = httpConnector.post("platId/" + PLAT_ID + "/txCode/" + txCode + "/transaction", req, signature)
                result = grails.converters.JSON.parse(res)
                if (result?.contract?.contractNo)
                {
                    def opportunityFlexFieldCategory = com.next.OpportunityFlexFieldCategory.findByOpportunityAndFlexFieldCategory(opportunity, com.next.FlexFieldCategory.findByName("用户合同"))
                    if (!opportunityFlexFieldCategory)
                    {
                        opportunityFlexFieldCategory = new com.next.OpportunityFlexFieldCategory(opportunity: opportunity, flexFieldCategory: com.next.FlexFieldCategory.findByName("用户合同")).save(flush: true)
                    }
                    def opportunityFlexField = com.next.OpportunityFlexField.findByNameAndCategory(contractType, opportunityFlexFieldCategory)
                    if (!opportunityFlexField)
                    {
                        opportunityFlexField = new com.next.OpportunityFlexField(name: contractType, category: opportunityFlexFieldCategory, description: contractType, dataType: "String")
                    }
                    opportunityFlexField.value = result?.contract?.contractNo
                    opportunityFlexField.save(flush: true)
                    result = ["message": "创建合同成功", code: "200"] as grails.converters.JSON
                }
                println("res:" + res)
            }
            else
            {
                result = ["message": "没有找到合同模板", code: "100"] as grails.converters.JSON
                println("res:" + result)
            }
        }
        else
        {
            result = ["message": "没有找到订单", code: "100"] as grails.converters.JSON
            println("res:" + result)
        }
        return result
    }

    /** @Description 安心签签署合同  3206
     * @Params params* @Return json* @Author Nagelan* @DateTime 2019/1/14 0014 15:14
     */
    def anxinqian3206 = { dataMap ->
        def JKS_PATH = dataMap.jksPath
        def JKS_PWD = "wc167xd"
        def ALIAS = "anxinsign"
        def PLAT_ID = "7EF27857582F4FD8E05312016B0A5DC1"
        def opportunity = com.next.Opportunity.findById(dataMap.opportunityId)
        def contractType = dataMap.contractType
        def file = dataMap.file
        def result
        def userId = com.next.FlexField.findByNameAndCategory("安心签企业userId", com.next.FlexFieldCategory.findByName("安心签企业认证账户"))?.defaultValue
        def contract = com.next.OpportunityFlexField.findByNameAndCategory(contractType, com.next.OpportunityFlexFieldCategory.findByOpportunityAndFlexFieldCategory(opportunity, com.next.FlexFieldCategory.findByName("用户合同")))?.value
        if (opportunity && contract && userId && file)
        {
            cfca.trustsign.demo.connector.HttpConnector httpConnector = new cfca.trustsign.demo.connector.HttpConnector()
            httpConnector.init(JKS_PATH, JKS_PWD)

            cfca.trustsign.common.vo.request.tx3.Tx3206ReqVO tx3206ReqVO = new cfca.trustsign.common.vo.request.tx3.Tx3206ReqVO()
            cfca.trustsign.common.vo.cs.HeadVO head = new cfca.trustsign.common.vo.cs.HeadVO()
            head.setTxTime(new java.util.Date().format("yyyyMMddHHmmss"))

            cfca.trustsign.common.vo.cs.SignContractVO signContract = new cfca.trustsign.common.vo.cs.SignContractVO()

            signContract.setContractNo(contract)
            cfca.trustsign.common.vo.cs.SignInfoVO signInfo = new cfca.trustsign.common.vo.cs.SignInfoVO()
            signInfo.setUserId(userId)
            signInfo.setLocation("211.94.108.226")
            //            signInfo.setProjectCode("0")
            //            signInfo.setIsCheckProjectCode(1)
            signInfo.setSignLocation("Signature1")
            signInfo.setAuthorizationTime(new java.util.Date().format("yyyyMMddHHmmss"))

            // 传图片或传sealId的方式任选其一，传图片优先级高
            signInfo.setImageData(file)
            // signInfo.setSealId("8C5E69F26A7E45F4977687301E120F83")
            signContract.setSignInfo(signInfo)

            tx3206ReqVO.setHead(head)
            tx3206ReqVO.setSignContract(signContract)

            String req = new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(tx3206ReqVO)
            String txCode = "3206"
            String signature = cfca.trustsign.demo.connector.SecurityUtil.p7SignMessageDetach(JKS_PATH, JKS_PWD, ALIAS, req)
            String res = httpConnector.post("platId/" + PLAT_ID + "/txCode/" + txCode + "/transaction", req, signature)
            result = grails.converters.JSON.parse(res)
            if (result?.signContract?.contractNo)
            {
                println "签署成功"
                result = ["message": "签署成功", code: "200"] as grails.converters.JSON
            }
            else
            {
                println "签署失败"
                result = ["message": "签署失败", code: "100"] as grails.converters.JSON
            }
        }
        else
        {
            result = ["message": "没有找到订单", code: "100"] as grails.converters.JSON
            println("res:" + result)
        }
        return result
    }

    def anxinqianDownloadContract = { dataMap ->
        def result
        def JKS_PATH = dataMap.jksPath
        def JKS_PWD = "wc167xd"
        def PLAT_ID = "7EF27857582F4FD8E05312016B0A5DC1"
        def opportunity = com.next.Opportunity.findById(dataMap.opportunityId)
        def contracts = com.next.OpportunityFlexField.findAllByCategory(com.next.OpportunityFlexFieldCategory.findByOpportunityAndFlexFieldCategory(opportunity, com.next.FlexFieldCategory.findByName("用户合同")))?.value
        def contractNos = ""
        if (contracts.size() > 0)
        {
            contracts.each {
                contractNos += it + "@"
            }
            contractNos = contractNos.substring(0, contractNos.lastIndexOf("@"))
        }
        cfca.trustsign.demo.connector.HttpConnector httpConnector = new cfca.trustsign.demo.connector.HttpConnector()
        httpConnector.init(JKS_PATH, JKS_PWD)
        if (contractNos)
        {
            byte[] fileBtye = httpConnector.getFile("platId/" + PLAT_ID + "/contractNos/" + contractNos + "/batchDownloading")
            if (fileBtye == null || fileBtye.length == 0)
            {
                result = null
            }
            else
            {
                result fileBtye
            }
        }
        return result
    }

    def contactSuccess()
    {
    }

    def getMaterialCheckView(Opportunity opportunity, String displayOrderStr)
    {
        def displayOrder = displayOrderStr ? displayOrderStr?.toInteger() : 0
        def category = OpportunityFlexFieldCategory.findByOpportunityAndFlexFieldCategory(opportunity, FlexFieldCategory.findByName("材料核验"))
        def flexFieldList = OpportunityFlexField.findAll("from OpportunityFlexField o where o.category.id = ? and o.displayOrder > ? order by o.displayOrder ASC", [category?.id, displayOrder])
        def materialView = ""
        for (
            def it in
                flexFieldList)
        {
            if (it?.value == '是')
            {
                materialView = it?.description
                displayOrder = it?.displayOrder
                break;
            }
        }
        if (materialView)
        {
            redirect action: materialView, id: opportunity?.id, params: [displayOrder: displayOrder]
            return
        }
        else
        {
            approveStage(opportunity)
        }
    }

    def businessCreditVerification(Opportunity opportunity)
    {
        respond opportunity
    }

    @Transactional
    def businessCreditVerificationSave(Opportunity opportunity)
    {
        approveStage(opportunity)
    }

    def businessCreditVerification1(Opportunity opportunity)
    {
        respond opportunity
    }

    @Transactional
    def businessCreditVerification1Save(Opportunity opportunity)
    {
        def opportunityFlexFieldCategory = OpportunityFlexFieldCategory.findByOpportunityAndFlexFieldCategory(opportunity, FlexFieldCategory.findByName("系统核查联系电话"))
        opportunityFlexFieldSave(opportunityFlexFieldCategory)

        opportunityFlexFieldCategory = OpportunityFlexFieldCategory.findByOpportunityAndFlexFieldCategory(opportunity, FlexFieldCategory.findByName("电话核查"))
        opportunityFlexFieldSave(opportunityFlexFieldCategory)

        opportunityFlexFieldCategory = OpportunityFlexFieldCategory.findByOpportunityAndFlexFieldCategory(opportunity, FlexFieldCategory.findByName("客户材料核查"))
        opportunityFlexFieldSave(opportunityFlexFieldCategory)

        opportunityFlexFieldCategory = OpportunityFlexFieldCategory.findByOpportunityAndFlexFieldCategory(opportunity, FlexFieldCategory.findByName("家访核查"))
        opportunityFlexFieldSave(opportunityFlexFieldCategory)

        approveStage(opportunity)
    }

    @Transactional
    def opportunityFlexFieldSave(OpportunityFlexFieldCategory opportunityFlexFieldCategory)
    {
        opportunityFlexFieldCategory?.fields?.each {
            def item = params[it?.name]
            if (item)
            {
                if (item instanceof String)
                {
                    it?.value = item
                }
                else
                {
                    def valueStr = ""
                    item?.each {
                        valueStr += "${it},"
                    }
                    it?.value = valueStr
                }
                it.save flush: true
            }
        }
    }

    def getAge(String idNumber)
    {
        def year = new Date().format("yyyy").toInteger()
        def date = new Date().format("MMdd").toInteger()
        def year1 = idNumber.substring(6, 10).toInteger()
        def date1 = idNumber.substring(10, 14).toInteger()
        def age = year - year1
        if (date < date1)
        {
            age = age - 1
        }
        age
    }

    /** @Description 中行发送验证码* @Params map* @Return boolean* @Author wangc* @Datetime 2019/1/24 002420:08
     */
    def sendMessage = { dataMap ->
        def getXmlInfo = { map ->
            StringBuilder sb = new StringBuilder()
            sb.append("<?xml version='1.0' encoding='utf-8'?> standalone='yes'")
            sb.append("<txnreq>")
            sb.append(" <head>")
            sb.append("     <TRN_CODE>WLS005</TRN_CODE>") //消息类型
            sb.append(" </head>")
            sb.append(" <data>")
            sb.append("     <MSG_TYPE>0</MSG_TYPE>") //消息类型
            sb.append("     <SYS_ID>FJX0</SYS_ID>") //应用系统代号  4位
            sb.append("     <ORG_ID>xml</ORG_ID>") //机构代号  10位
            sb.append("     <TERM_ID>0000000</TERM_ID>") //终端代号
            sb.append("     <TELL_NO>000000</TELL_NO>") //柜员代号
            sb.append("     <SRV_CODE>box</SRV_CODE>") //业务代码  12位
            sb.append("     <TXN_DATE>${new Date().format('YYYYMMDD')}</TXN_DATE>") //交易日期
            sb.append("     <TXN_TIME>${new Date().format('HHMMSS')}</TXN_TIME>") //交易时间
            sb.append("     <SND_COUNT>001</SND_COUNT>") //发送总条数
            sb.append("     <TRACE_NO>00000000000000000000</TRACE_NO>") //流水号
            sb.append("     <BAK_FLD1></BAK_FLD1>") //备注域1
            sb.append("     <BAK_FLD2></BAK_FLD2>") //备注域2
            sb.append("     <RPT_FLAG>0</RPT_FLAG>") //是否需要状态报告
            sb.append("     <MODE_NO>2000028052</MODE_NO>") //模板号
            sb.append("     <MSG_CONT>中国银行~验证码~${map.code}</MSG_CONT>") //发送信息内容 “~”分隔
            sb.append("     <TAG_TEL>${map.cellphone}</TAG_TEL>") //目的手机号
            sb.append("     <SEND_TIME>00000000000000</SEND_TIME>") //定时发送时间
            sb.append("     <VALID_TIME>0000</VALID_TIME>") //短信失效时间
            sb.append("     <TIME_OUT>0000</TIME_OUT>") //超时
            sb.append("     <BAK_FLD1></BAK_FLD1>") //备注域1
            sb.append("     <BAK_FLD2></BAK_FLD2>") //备注域2
            sb.append(" </data>")
            sb.append("</txnreq>")

            return String.format("%05d", sb.toString().length()) + sb.toString()
        }
        def flat = false
        def map = [:]
        map.code = dataMap.verifiedCode
        map.cellphone = dataMap.cellphone
        def data = getXmlInfo(map)
        def socket = new java.net.Socket("22.220.32.54", 7999)
        socket.withObjectStreams { input, output ->
            try
            {
                output << data
                socket.shutdownOutput()
                println("发送短信完毕")
                flat = true
            }
            catch (IOException e)
            {
                println "发送验证码给${dataMap.cellphone}：${dataMap.verifiedCode}失败" + e
            }
        }
        return flat
    }

    def getCityByProvinceId()
    {
        render([list: City.findAllByProvince(Province.findById(params['provinceId']))] as JSON)
    }

    def getDistrictByCityId()
    {
        render([list: District.findAllByCity(City.findById(params['cityId']))] as JSON)
    }

    def batchAttachmentInsert(Opportunity opportunity, String attachmentUrl, String attachmentType)
    {
        def attachmentUrlList = attachmentUrl?.split(",")
        attachmentUrlList?.each {
            if (it)
            {
                def attachments = new Attachments()
                attachments.opportunity = opportunity
                attachments.type = AttachmentType.findByName(attachmentType)
                attachments.fileName = "http://quickloanfs.cindata.cn/" + it
                attachments.thumbnailUrl = "http://quickloanfs.cindata.cn/" + it
                attachments.fileUrl = "http://quickloanfs.cindata.cn/" + it
                if (attachments.validate())
                {
                    attachments.save flush: true
                }
                else
                {
                    println attachments.errors
                }
            }
        }
    }

    //面签app审核订单信息
    def appOpportunity1(Opportunity opportunity)
    {
        def code = 200
        def message = "返回成功"
        def data = new ArrayList()

        if (opportunity)
        {
            //身份证信息
            def map = new HashMap()
            def picMap = new HashMap()
            picMap.img1 = Attachments.findByOpportunityAndType(opportunity, AttachmentType.findByName("借款人身份证正面"))?.fileUrl
            picMap.img2 = Attachments.findByOpportunityAndType(opportunity, AttachmentType.findByName("借款人身份证反面"))?.fileUrl

            map.key = "客户证件信息"
            map.values = picMap
            data.add(map)
            //客户信息
            def clientMap = new HashMap<Object, Object>()
            clientMap.key = "客户信息"
            def clientList = new ArrayList<Object>()
            clientList.add([title: "客户姓名", detail: opportunity?.fullName])
            clientList.add([title: "身份证号", detail: opportunity?.idNumber])
            clientMap.values = clientList
            data.add(clientMap)
        }
        else
        {
            code = 400
            message = "返回失败,订单不存在"
        }
        render([code: code, message: message, data: data] as JSON)

    }

    //app审核状态
    def loginStatus()
    {
        def json = request.JSON
        println "****************  loginStatus  *********************"
        println json
        def name = json['model']
        def version = json['version']
        def appVersion = AppVersion.findByAppNameAndAppVersion(name, version)
        def configuration = AppConfiguration.findByKeyAndAppVersion(AppConfigurationKey.findByName("appApproveStatus"), appVersion)
        def status = configuration?.value

        println "approvestatus: " + status
        render([code: status] as JSON)

    }

    def userPrivacy()
    {
    }

    def businessApplicationForm(Opportunity opportunity)
    {
        respond opportunity
    }

    //       信用卡领用合约
    def creditCardAgreement()
    {
    }

    /** @Description 发送R系统报文
     * @Params opportunity
     * @Return null
     * @Author wangc
     * @Datetime 2019/2/22 002210:15
     */
    def sendInfoToRSystem = { dataMap ->
        def result
        def map
        com.next.Opportunity opportunity = dataMap.opportunity
        com.next.Contact contact = opportunity?.contact
        com.next.BankAccount bankAccount = com.next.OpportunityBankAccount.findByOpportunityAndType(opportunity,com.next.BankAccountType.findByName("信用卡"))?.bankAccount
        if(opportunity){
            def getXmlInfo = { map1 ->
                def mapinfo
                StringBuilder sb = new StringBuilder()
                sb.append("<?xml version='1.0' encoding='utf-8'?> standalone='yes'")
                sb.append("<MSG>")
                sb.append(" <HEAD>")
                sb.append("     <MSGTYPE>0100</MSGTYPE>")     //报文类型
                sb.append("     <CUSTYPE>01</CUSTYPE>")     //客户类型
                sb.append("     <TRAN_CODE>RLCOL101</TRAN_CODE>")     //交易码
                sb.append("     <LAUNCHERID>015</LAUNCHERID>")     //发起方标志
                sb.append("     <PLATID>015</PLATID>")     //平台号
                sb.append("     <REQUEST_DATE>${new java.util.Date().format('YYYYMMDD')}</REQUEST_DATE>")     //交易请求日期
                sb.append("     <REQUEST_TIME>${new java.util.Date().format('HHmmss')}</REQUEST_TIME>")     //交易请求事件
                sb.append("     <RESSYSTEM_ID>015</RESSYSTEM_ID>")     //响应方标志
//                sb.append("     <RESPOND_DATE>RESPOND_DATE</RESPOND_DATE>")     //交易响应日期
//                sb.append("     <RESPOND_TIME>RESPOND_TIME</RESPOND_TIME>")     //交易响应时间
                sb.append("     <REQ_TRACENO>${java.util.UUID.randomUUID().toString()}</REQ_TRACENO>")     //UUID 请求方必填
//                sb.append("     <RES_TRACENO>RES_TRACENO</RES_TRACENO>")     //UUID 响应方系统必填
//                sb.append("     <RETCODE>RETCODE</RETCODE>")     //交易结果返回码
//                sb.append("     <ERRORMSG>ERRORMSG</ERRORMSG>")     //错误原因
//                sb.append("     <SIGNATURE>SIGNATURE</SIGNATURE>")     //签名
//                sb.append("     <RESERVE_FIELD>RESERVE_FIELD</RESERVE_FIELD>")     //备用域
                sb.append(" </HEAD>")
                sb.append(" <BODY>")
                sb.append("     <PLATSEQNO>${opportunity?.serialNumber}</PLATSEQNO>")     //平台流水号
                sb.append("     <CUSTINFO>")     //客户信息
                sb.append("         <CUSTNO></CUSTNO>")     //客户号
                sb.append("         <CUSTLSTNM>${contact?.lastName}</CUSTLSTNM>")     //报文类型
                sb.append("         <CUSTFSTNM>${contact?.firstName}</CUSTFSTNM>")     //报文类型
                sb.append("         <SEXID>${contact?.gender=="男"?"1":"0"}</SEXID>")     //报文类型
                mapinfo = ["未婚":"0","已婚":"1","初婚":"2","再婚":"3","复婚":"4","丧偶":"5","离婚":"6","其它":"7"]
                sb.append("         <PERMRTST>${mapinfo.get(contact?.maritalStatus)}</PERMRTST>")     //婚姻状况
                sb.append("         <CBIBTHDT>${contact?.birthday?.format("YYYYMMDD")}</CBIBTHDT>")     //出生日期
                sb.append("         <CERTY>01</CERTY>")     //证件类型
                sb.append("         <CERNO>${contact?.idNumber}</CERNO>")     //证件号码
//                sb.append("         <PERVISATP>PERVISATP</PERVISATP>")     //签证类型
//                sb.append("         <PERVISAENDDT>PERVISAENDDT</PERVISAENDDT>")     //签证到期日
                sb.append("         <PERCEROP>${contact?.authority}</PERCEROP>")     //发证机关
                sb.append("         <PERCERDT>${contact?.periodOfValidity}</PERCERDT>")     //证件到期日
                sb.append("         <PERNTTNO>CN</PERNTTNO>")     //国家/地区（国籍）
                sb.append("         <PERLANGE>01</PERLANGE>")     //通讯语言
                sb.append("         <PERISDEN>1</PERISDEN>")     //是否为居民
//                sb.append("         <PERNTTNO2>PERNTTNO2</PERNTTNO2>")     //第二国籍
                sb.append("         <OTHERCUSTNM>${contact?.lastNameSpell}</OTHERCUSTNM>")     //姓（拼音）
                sb.append("         <OTHERLSTNM>${contact?.firstNameSpell}</OTHERLSTNM>")     //名（拼音）
                sb.append("         <PERLIVNTT>CN</PERLIVNTT>")     //居住国家和地区
                sb.append("         <FACTAID>02</FACTAID>")     //FAIRS客户分类
//                sb.append("         <TIN>TIN</TIN>")     //纳税人识别号（TIN）
//                sb.append("         <TINENDT>TINENDT</TINENDT>")     //纳税人识别号到期日
//                sb.append("         <PSTCD>PSTCD</PSTCD>")     //证件地址行邮编
//                sb.append("         <CTFADDR4>CTFADDR4</CTFADDR4>")     //证件地址行4（国家）
//                sb.append("         <CTFADDR3>CTFADDR3</CTFADDR3>")     //证件地址行3（省）
//                sb.append("         <CTFADDR2>CTFADDR2</CTFADDR2>")     //证件地址行2（市）
//                sb.append("         <CTFADDR1>CTFADDR1</CTFADDR1>")     //证件地址行1（详细地址）
//                sb.append("         <FAMILYCOUNTRYCODE>FAMILYCOUNTRYCODE</FAMILYCOUNTRYCODE>")     //住宅电话国家码
//                sb.append("         <FAMAREACODE>FAMAREACODE</FAMAREACODE>")     //住宅电话地区码
//                sb.append("         <HOUSETELNO>HOUSETELNO</HOUSETELNO>")     //住宅电话
                sb.append("         <TELEPHONECOUNTRYCODE>86</TELEPHONECOUNTRYCOD>")     //移动电话国家码
                sb.append("         <REALPERMBLAREACODE>86</REALPERMBLAREACODE>")     //移动电话地区码 TODO
                sb.append("         <REALPERMBLNO>${contact?.cellphone}</REALPERMBLNO>")     //移动电话
                sb.append("         <EMAIL>${contact?.email}</EMAIL>")     //EMAIL地址
                sb.append("         <FAMPSTCD>${contact?.zipCode}</FAMPSTCD>")     //常住地址邮编
                sb.append("         <FAMADDR4>${contact?.country?.name}</FAMADDR4>")     //常住地址（国家）
                sb.append("         <FAMADDR3>${contact?.province?.name}</FAMADDR3>")     //常住地址（省）
                sb.append("         <FAMADDR2>${contact?.city?.name}</FAMADDR2>")     //常住地址（市）
                sb.append("         <FAMADDR1>${contact?.address}</FAMADDR1>")     //常住地址1（详细地址）
                mapinfo = ["外籍":"0","港澳台":"1","外省":"2","本省":"3","本地":"4"]
                sb.append("         <DOMICILE>${mapinfo.get(contact?.householdRegistrationType)}</DOMICILE>")     //客户户籍
                sb.append("         <CUSDMCLR>${contact?.authority}</CUSDMCLR>")     //户籍所在地
                mapinfo = ["中国共产党中央委员会和地方各级组织负责人":"01","国家机关及其工作机构负责人":"02","民主党派、社会团体及工作机构负责人":"03","事业单位负责人":"04","企业负责人":"05","科学研究人员":"11","工程技术（计算机）人员":"13","农业技术人员":"17","飞行和船舶技术等人员":"18","卫生专业技术人员":"19","经济业务人员":"21","金融业务人员":"22","法律专业人员":"23","教学人员":"24","文学艺术工作人员":"25","体育工作人员":"26","新闻出版、文化工作人员":"27","其他专业技术人员":"29","会计师":"30","行政办公人员":"31","安全保卫和消防工作人员":"32","邮政和电信业务人员":"33","事业单位员工":"34","其他办事人员和有关人员":"39","商业、服务业人员":"40","农、林、牧、渔、水利业生产人员":"50","生产、运输设备操作人员及有关人员":"60","军人":"X0","学生":"Y1","外交人员":"Y2","私营业主":"Y3","不便分类的其他从业人员":"Y9","无职业活动人员":"Z0","退休人员":"Z1","家庭主妇":"Z2"]
                sb.append("         <OCCUPATION>${mapinfo.get(contact?.profession?.name)}</OCCUPATION>")     //职业
                mapinfo = ["汉族":"01","阿昌族":"02","白族":"03","保安族":"04","布朗族":"05","布依族":"06","朝鲜族":"07","达斡尔族":"08","傣族":"09","德昂族":"10","东乡族":"11","独龙族":"12","俄罗斯族":"13","鄂伦春族":"14","鄂温克族":"15","高山族":"16","哈尼族":"17","哈萨克族":"18","赫哲族":"19","回族":"20","基诺族":"21","京族":"22","景颇族":"23","柯尔克孜族":"24","拉祜族":"25","黎族":"26","傈僳族":"27","珞巴族":"28","满族":"29","毛南族":"30","门巴族":"31","蒙古族":"32","苗族":"33","仫佬族":"34","纳西族":"35","怒族":"36","普米族":"37","羌族":"38","撒拉族":"39","畲族":"40","水族":"41","塔吉克族":"42","塔塔尔族":"43","侗族":"44","土族":"45","土家族":"46","佤族":"47","维吾尔族":"48","乌孜别克族":"49","锡伯族":"50","瑶族":"51","彝族":"52","仡佬族":"53","裕固族":"54","藏族":"55","壮族":"56","其他":"99"]
                sb.append("         <PERNTLNO>${mapinfo.get(contact?.nation)}</PERNTLNO>")     //民族
                mapinfo = ["无":"0","高级":"1","中级":"2","初级":"3","未知":"4"]
                sb.append("         <POSTTITLE>${mapinfo.get(contact?.professionTile?.name)}</POSTTITLE>")     //职称
                mapinfo = ["高级领导（行政级别局级及局级以上领导或大公司高级管理人员）":"1","中级领导（行政级别局级以下领导或大公司中级管理人员）":"2","一般员工":"3"]
                sb.append("         <POSITION>${mapinfo.get(contact?.job)}</POSITION>")     //职务
                mapinfo = ["研究生":"1","大学本科（简称“大学”）":"2","大学专科和专科学校（简称“大专”）":"3","中等专业学校或中等技术学校":"4","技术学校":"5","高中":"6","初中":"7","小学":"8","文盲或半文盲":"9"]
                sb.append("         <PEREDUBK>${mapinfo.get(contact?.certificate?.name)}</PEREDUBK>")     //文化程度
                mapinfo = ["名誉博士":"0","博士":"1","硕士":"2","学士":"3","其他":"4"]
                sb.append("         <PEREDULV>${mapinfo.get(contact?.highestCertificate?.name)}</PEREDULV>")     //最高学位
//                sb.append("         <PERSCLNM>PERSCLNM</PERSCLNM>")     //毕业院校
                sb.append("         <PERWOKDT>${contact?.workTime?.format("YYYYMMDD")}</PERWOKDT>")     //参加工作日期
                sb.append("         <WKIBEDAT>${contact?.currentWorkTime?.format("YYYYMMDD")}</WKIBEDAT>")     //现工作日期
                mapinfo = ["自置":"1","按揭":"2","亲属楼宇":"3","集体宿舍":"4","租房":"5"]
                sb.append("         <PERHOMSO>${mapinfo.get(contact?.houseOrigin?.name)}</PERHOMSO>")     //现住房来源及居住状况
                sb.append("         <PERNLVDT>${contact?.residentialDuration?.replace("-","")}</PERNLVDT>")     //现住址时间
                sb.append("         <INSECNTP>D01</INSECNTP>")     //国民经济部门
                sb.append("         <PERCMPNM>${contact?.companyName}</PERCMPNM>")     //现工作单位
                mapinfo = ["医院":"01","教育":"02","金融/保险":"03","公共管理与社会组织":"04","科学研究，技术服务业和地质勘察业":"05","信息传输、计算机服务、软件和技术服务业":"06","国际性组织":"07","工商服务业":"08","水利、环境与公共设施管理行业":"09","电力，燃气及水的生产及供应业":"10","制造业":"11","建筑业":"12","交通运输，仓储和邮政业":"13","批发和零售业":"14","房地产业":"15","租赁及商业":"16","文化，体育和娱乐业":"17","采掘业":"18","住宿和餐饮业":"19","农业、林业、牧业、渔业":"20","居民服务以及其他服务行业":"21","临时工":"22","退休":"23","家庭妇女":"24","学生":"25","待业":"26","其他":"27","进出口贸易业":"28","旅游业":"29","机关事业单位及部队":"30"]
                sb.append("         <WKIBUSTY>${mapinfo.get(contact?.industry?.name)}</WKIBUSTY>")     //本单位行业
                sb.append("         <COMPANYCOUNTRYCODE>86</COMPANYCOUNTRYCODE>")     //单位电话国家码
                sb.append("         <CMPAREACODE>010</CMPAREACODE>")     //单位电话地区码 TODO
                sb.append("         <CMPTELNO>${contact?.companyPhone}</CMPTELNO>")     //单位电话
                sb.append("         <PERRGCPT>9</PERRGCPT>")     //单位注册资本  TODO
                sb.append("         <CMPPSTCD>${contact?.companyZipCode}</CMPPSTCD>")     //工作单位邮编
                sb.append("         <CMPADDR4>中国</CMPADDR4>")     //工作单位地址4（国家） TODO
                sb.append("         <CMPADDR3>${contact?.companyProvince?.name}</CMPADDR3>")     //工作单位地址3（省）
                sb.append("         <CMPADDR2>${contact?.companyCity?.name}</CMPADDR2>")     //工作单位地址2（市）
                sb.append("         <CMPADDR1>${contact?.companyAddress}</CMPADDR1>")     //工作单位地址1（详细地址）
                mapinfo = ["未知":"0","工资卡和定期存款":"1","仅有工资卡":"2","仅有定期存款":"3"]
                sb.append("         <BANKACCINF>${mapinfo.get(contact?.bankDealings)}</BANKACCINF>")     //银行往来情况
                mapinfo = ["3~4年":"0","1~2年":"1","1年以下":"2","新客户":"3","未知":"4","5年或以上":"5"]
                sb.append("         <BOCCLIENT>${mapinfo.get(contact?.beCustomerDuration)}</BOCCLIENT>")     //成为中行客户时间
//                sb.append("         <OPENBK>OPENBK</OPENBK>")     //开户银行
//                sb.append("         <SALARYAC>SALARYAC</SALARYAC>")     //工资账号
                sb.append("         <MONTHINCOMEMON>${contact?.monthlyIncome}</MONTHINCOMEMON>")     //主借款人月收入（元）
                mapinfo = ["工资":"0","投资":"1","其他":"2"]
                sb.append("         <INCOMETYPE>${mapinfo.get(contact?.monthlyIncomeType)}</INCOMETYPE>")     //主借款人收入类型
                mapinfo = ["收入证明":"0","行卡流水":"1","社保记录":"2","公积金记录":"3","纳税记录":"4","其他，请注明":"5"]
                sb.append("         <VALIDATEWAY>${mapinfo.get(contact?.monthlyIncomeVerifyMethod)}</VALIDATEWAY>")     //主借款人月收入验证方式
                sb.append("         <INCOMEREMARK>${contact?.monthlyIncomeVerifyMethodMemo}</INCOMEREMARK>")     //主借款人月收入验证方式注明
                sb.append("         <FAMILYOTHERSALARY>${contact?.otherMembersMonthlyIncome}</FAMILYOTHERSALARY>")     //家庭其他成员月收入（元）
                sb.append("         <OTHVALIDATEWAY>${mapinfo.get(contact?.otherMembersMonthlyIncomeVerifyMethod)}</OTHVALIDATEWAY>")     //家庭其他成员月收入验证方式
                sb.append("         <OTHERREMARK>${contact?.othersIncomeVerifyMemo}</OTHERREMARK>")     //家庭其他成员月收入验证方式注明
//                sb.append("         <PERMTHTOUT>${contact?.companyAddress}</PERMTHTOUT>")     //关系人月支出合计 （元）
//                sb.append("         <FAMPERHMNCS>${contact?.companyAddress}</FAMPERHMNCS>")     //家庭月支出合计 （元）
//                sb.append("         <FAMPERHMSTK>FAMPERHMSTK</FAMPERHMSTK>")     //家庭股票额 （元）
//                sb.append("         <FAMPERHMBND>FAMPERHMBND</FAMPERHMBND>")     //家庭债券额（元）
//                sb.append("         <FAMPERHMDPS>FAMPERHMDPS</FAMPERHMDPS>")     //家庭存款总额 （元）
//                sb.append("         <FAMPERHMHOUVAL>FAMPERHMHOUVAL</FAMPERHMHOUVAL>")     //家庭现有住房价格（元）
//                sb.append("         <FAMPERHMCARVAL>FAMPERHMCARVAL</FAMPERHMCARVAL>")     //家庭现有汽车价格（元）
//                sb.append("         <FAMPERHMDCS>FAMPERHMDCS</FAMPERHMDCS>")     //家庭月债务支出（元）
//                sb.append("         <PERSFOAM>PERSFOAM</PERSFOAM>")     //家庭月养老金额（元）
//                sb.append("         <FAMPERINSAM>FAMPERINSAM</FAMPERINSAM>")     //家庭人寿保险单价值（元）
                sb.append("         <SPONAMOUNT>0</SPONAMOUNT>")     //为他人担保额（元）
//                sb.append("         <FAMPERHMAST>FAMPERHMAST</FAMPERHMAST>")     //家庭总资产（元）
                sb.append("         <FAMPERHMDBT>0</FAMPERHMDBT>")     //家庭总负债（元）
                mapinfo = ["商品":"1","房改":"2","安居":"3","集资":"4","宅基":"5","其他":"6"]
                sb.append("         <PERHOMKD>${mapinfo.get(contact?.houseType?.name)}</PERHOMKD>")     //现住房种类
//                sb.append("         <PERHOMAR>${contact?.othersIncomeVerifyMemo}</PERHOMAR>")     //现住房面积（平方米）
                mapinfo = ["政府各级领导":"0","中行授信单位中层以上领导":"1","员工或员工担保":"2","存款大户":"3","理财客户":"4","其他":"5"]
                sb.append("         <CLIENTCHR>${mapinfo.get(contact?.contactCharacter)}</CLIENTCHR>")     //客户特征
                mapinfo = ["未知":"0","4张以上":"1","2-3张":"2","1张":"3","0张":"4"]
                sb.append("         <PERHMCAD>${mapinfo.get(contact?.cardCountRange)}</PERHMCAD>")     //持卡情况
//                sb.append("         <PERVIPNO>${contact?.othersIncomeVerifyMemo}</PERVIPNO>")     //VIP卡号
//                sb.append("         <PERTYPE>${contact?.othersIncomeVerifyMemo}</PERTYPE>")     //客户分层
                mapinfo = ["00":"00+","01":"01+","01-":"01-","02":"02+","02-":"02-","03":"03+","03-":"03-","04":"04+","04-":"04-","05":"05+","05-":"05-","06":"06+","06-":"06-","07":"07+","07-":"07-","08":"08+","08-":"08-","09":"09+","09-":"09-","10":"10+","10-":"10-","99":"99+"]
                sb.append("         <PERCRDPT>${mapinfo.get("00")}</PERCRDPT>")     //客户级别
                mapinfo = ["AAA":"00","AA":"01","A":"02","BBB+":"03","BBB":"04","BBB-":"05","BB+":"06","BB":"07","BB-":"08","B+":"09","B":"10","B-":"11","CCC":"12","CC":"13","C":"14","D":"15","不评级":"16","未评级":"17"]
                sb.append("         <PERCRCLS>${mapinfo.get("未评级")}</PERCRCLS>")     //个人客户信用等级  TODO
                sb.append("         <HVTWOHSFLG>${contact?.isProvideResidentCertificate?"0":"1"}</HVTWOHSFLG>")     //是否提供居留证明
                sb.append("         <HVCMPCHARTERFLG>${contact?.isProvideBusinessLicense?"0":"1"}</HVCMPCHARTERFLG>")     //是否提供任职单位营业执照
                sb.append("         <FAMPERHMMEM>${contact?.familyMembersCount}</FAMPERHMMEM>")     //家庭成员数（人）
                sb.append("         <PERHMPER>${contact?.fendCount}</PERHMPER>")     //供养人口数（人）
                mapinfo = ["开发商/经销商员工":"0","建筑企业员工":"1","开发商/经销商关联企业员工":"2","其他关联客户":"3","非关联人":"4"]
                sb.append("         <PERGDCAD>${mapinfo.get(contact?.contactMarkupOfConsumerLoan)}</PERGDCAD>")     //消贷关联客户标记
                mapinfo = ["本行员工":"0","VIP客户":"1","理财客户":"2","分行推荐客户":"3","其他":"4"]
                sb.append("         <PERSOURC>${mapinfo.get(contact?.contactSourceOfConsumerLoan)}</PERSOURC>")     //消贷客户来源
                mapinfo = ["否":"0","是":"1","9":"9"]
                sb.append("         <PERRELFG>${mapinfo.get("9")}</PERRELFG>")     //关联客户标志
                mapinfo = ["刑事犯罪":"0","其他犯罪":"1","无违法记录":"3","9":"9"]
                sb.append("         <PERCRMFG>${mapinfo.get("9")}</PERCRMFG>")     //违法记录标志
                mapinfo = ["未知":"0","不定期合同":"1","定期合同":"2","无合同":"3","其它种类合同":"4"]
                sb.append("         <PERCONTY>${mapinfo.get("定期合同")}</PERCONTY>")     //工作合同类型 TODO
//                sb.append("         <PERINSNO>${perinsno.get(contact?.contactMarkupOfConsumerLoan)}</PERINSNO>")     //个人保险号
//                sb.append("         <LINKNM>LINKNM</LINKNM>")     //联系人姓名
//                sb.append("         <LINKTELNO>LINKTELNO</LINKTELNO>")     //联系人联系电话
//                sb.append("         <LINKEMAIL>LINKEMAIL</LINKEMAIL>")     //联系人电子邮件
//                sb.append("         <PFC_AREA>PFC_AREA</PFC_AREA>")     //公积金缴纳区域码
//                sb.append("         <PFC_CODE>PFC_CODE</PFC_CODE>")     //公积金中心编码
//                sb.append("         <PFC_AUTH>PFC_AUTH</PFC_AUTH>")     //公积金授权码
//                sb.append("         <IS_QUERY_OPERATOR>IS_QUERY_OPERATOR</IS_QUERY_OPERATOR>")     //是否查询手机运营商
                sb.append("     </CUSTINFO>")
                sb.append("     <LOANINFO>")     //贷款信息
                mapinfo = ["汽车分期":"FQ0001PLJA","汽车衍生消费分期":"FQ0010PLJJ","家装分期":"FQ0002PLJM"]
                sb.append("         <PRODUCT_DETAIL_CODE>${mapinfo.get(opportunity?.product?.name)}</PRODUCT_DETAIL_CODE>")     //产品细类码
                mapinfo = ["网银":"01","手机银行":"02","微信":"03","商户":"04","网点":"05","缤纷生活":"06","网申":"07"]
                sb.append("         <CHANNO>${mapinfo.get("网点")}</CHANNO>")     //渠道标识  TODO 未找到
                mapinfo = ["是":"Y","否":"N"]
                sb.append("         <IS_REF_INSTALLMENT>${mapinfo.get("否")}</IS_REF_INSTALLMENT>")     //是否关联汽车衍生分期  TODO 未找到
                mapinfo = ["是":"Y","否":"N"]
                sb.append("         <OPEN_CARD_FLG>${mapinfo.get("否")}</OPEN_CARD_FLG>")     //是否开卡 TODO 未找到
                mapinfo = ["是":"Y","否":"N"]
                sb.append("         <VISIT_FLG>${mapinfo.get("否")}</VISIT_FLG>")     //是否已经三亲见 TODO 未找到
                mapinfo = ["是":"Y","否":"N"]
                sb.append("         <MANAGER_VALIDATE>${mapinfo.get("否")}</MANAGER_VALIDATE>")     //是否需要客户经理验证码 TODO
                mapinfo = ["低":"0","中":"1","高":"2"]
                sb.append("         <PRIORITY>${mapinfo.get(bankAccount?.priority)}</PRIORITY>")     //优先级
                sb.append("         <BNKNO>${opportunity?.user?.account?.name}</BNKNO>")     //所属经办机构
                sb.append("         <TLRNO>${opportunity?.user?.fullName}</TLRNO>")     //所属客户经理
                sb.append("     </LOANINFO>")
                sb.append("     <CARDINFO>")     //开卡信息
                sb.append("         <TYPECODE>${bankAccount?.code}</TYPECODE>")     //卡面代码
                sb.append("         <CARDNAME>${bankAccount?.name}</CARDNAME>")     //卡面简称
                mapinfo = ["申请":"Y","不申请":"N"]
                sb.append("         <ZEROCREDITLIMITFLAG>${bankAccount.circulationQuota?"Y":"N"}</ZEROCREDITLIMITFLAG>")     //否申请循环额度
                mapinfo = ["手机":"C","E-mail + 手机":"G","E-mail":"2"]
                sb.append("         <BILLSEND>${mapinfo.get(bankAccount?.billSentMethod)}</BILLSEND>")     //对账单发送方式选择
                mapinfo = ["寄往单位地址":"1","寄往住宅地址":"2"]
                sb.append("         <BILLADDRIND>${mapinfo.get(bankAccount?.postAddressType)}</BILLADDRIND>")     //帐单卡片寄送地址选择  TODO  不确定
                mapinfo = ["国航":"1","南航":"2","深航":"3"]
                sb.append("         <MCAIRLINE>${mapinfo.get("南航")}</MCAIRLINE>")     //航空里程自动兑换功能  TODO  未找到
                mapinfo = ["密码+签名":"1","签名":"2"]
                sb.append("         <CONSUME>${mapinfo.get(bankAccount?.creditCardPayMethod)}</CONSUME>")     //刷卡消费方式选择
                sb.append("         <MEMBERSNO>MEMBERSNO</MEMBERSNO>")     //会员号  TODO 不确定
                mapinfo = ["政府机关/事业单位":"11","国营企业":"12","个体经营/自由职业":"13","民营企业":"14","股份制公司":"15","三资企业":"16","军队":"17","其他":"18"]
                sb.append("         <EMPLBIZTYPE>${mapinfo.get(contact?.companyEconomyType?.name)}</EMPLBIZTYPE>")     //经济类型  TODO 不确定
                sb.append("         <ISACCOUNTMANAGER>${bankAccount?.connectmanIsClientManager?"1":"0"}</ISACCOUNTMANAGER>")     //联系人是否是客户经理
                if (!bankAccount?.connectmanIsClientManager){
                    def connect = com.next.OpportunityContact.findByOpportunityAndContact(opportunity,contact)
                    if (connect?.connectedContact){
                        sb.append("         <CONTACTNAME>${connect?.connectedContact?.fullName}</CONTACTNAME>")     //联系人姓名
                        mapinfo = ["父母":"11","配偶":"12","亲戚":"13","其它":"14"]
                        sb.append("         <CONTACTRELSHIP>${mapinfo.get(connect?.connectedType?.name)}</CONTACTRELSHIP>")     //联系人与申请人关系
                        sb.append("         <CONTACTPHONENUM>${connect?.connectedContact?.cellphone}</CONTACTPHONENUM>")     //联系人手机号
                        sb.append("         <CONTACTEMPLOYER>${connect?.connectedContact?.companyName}</CONTACTEMPLOYER>")     //联系人单位名称
//                        sb.append("         <CONTACTPHONESTATE>${connect?.connectedContact?.fullName}</CONTACTPHONESTATE>")     //联系人电话区号
//                        sb.append("         <CONTACTPHONE>CONTACTPHONE</CONTACTPHONE>")     //联系人电话号码
//                        sb.append("         <CONTACTPHONEEXT>CONTACTPHONEEXT</CONTACTPHONEEXT>")     //联系人电话分机
                    }
                }else {
                    sb.append("         <YUNTBANKADDRSTATE>${opportunity?.user?.city?.province?.name}</YUNTBANKADDRSTATE>")     //客户经理单位省/直辖市   TODO
                    sb.append("         <YUNTBANKADDRCITY>${opportunity?.user?.city?.name}</YUNTBANKADDRCITY>")     //客户经理单位市/区/县
//                    sb.append("         <YUNTBANKADDR2>${}</YUNTBANKADDR2>")     //客户经理详细地址2
//                    sb.append("         <YUNTBANKADDR3>${}</YUNTBANKADDR3>")     //客户经理详细地址3
                    sb.append("         <YUNTMANAGERIDNUMBER>${opportunity?.user?.idNumber}</YUNTMANAGERIDNUMBER>")     //客户经理身份证号码
                    sb.append("         <YUNTMANAGERNO>***</YUNTMANAGERNO>")     //客户经理员工号  todo
                }
                mapinfo = ["主动还款":"0","自动还款":"1"]
                sb.append("         <MCPAYMETHOD>${mapinfo.get(bankAccount?.creditCardPaymentMethod)}</MCPAYMETHOD>")     //还款方式
                if (bankAccount?.creditCardPaymentMethod == "自动还款"){
//                    sb.append("         <APAYSELECT>APAYSELECT</APAYSELECT>")     //还款金额选择
//                    sb.append("         <APAYOPTION>APAYOPTION</APAYOPTION>")     //还款帐户选项
                    sb.append("         <BRANCHNAME>${bankAccount?.address}</BRANCHNAME>")     //开户行所在省市
//                    sb.append("         <APAYACCUSD>APAYACCUSD</APAYACCUSD>")     //外币账号
                    sb.append("         <APAYACCRMB>${bankAccount?.numberOfAccount}</APAYACCRMB>")     //人民币账号
                }
//                sb.append("         <MCMOTHERNAME>MCMOTHERNAME</MCMOTHERNAME>")     //母亲姓氏
//                sb.append("         <MCKNOWASNAME2>MCKNOWASNAME2</MCKNOWASNAME2>")     //主卡人第二印花名
//                sb.append("         <MCEMPLPHONEEXT>MCEMPLPHONEEXT</MCEMPLPHONEEXT>")     //单位电话分机
//                sb.append("         <BANKINFOCC>BANKINFOCC</BANKINFOCC>")     //CC（营销活动代号）
//                sb.append("         <BANKINFOPCCIN>BANKINFOPCCIN</BANKINFOPCCIN>")     //IN（营销人员代码）
//                sb.append("         <BANKINFON>BANKINFON</BANKINFON>")     //PN（联名机构代码）
//                sb.append("         <BANKINFOEX>BANKINFOEX</BANKINFOEX>")     //EX（外部识别码）
//                sb.append("         <RECOMMENDPHONE>RECOMMENDPHONE</RECOMMENDPHONE>")     //推荐人手机号
//                sb.append("         <BANKINFOFEETYPE>BANKINFOFEETYPE</BANKINFOFEETYPE>")     //免年费类型
//                sb.append("         <ISINCREASE>ISINCREASE</ISINCREASE>")     //是否有增额意愿
//                sb.append("         <APPLYTYPE>APPLYTYPE</APPLYTYPE>")     //申请信用卡类型
                sb.append("     </CARDINFO>")
                if (opportunity?.product?.name == "家装分期"){
                    def house = com.next.House.findByOpportunity(opportunity)
                    sb.append("     <RETAILINFO>")     //交易信息
//                    sb.append("         <WCISALECMP>WCISALECMP</WCISALECMP>")     //经销商客户号
                    sb.append("         <LCTBLDAR>${house?.area}</LCTBLDAR>")     //建筑面积（平方米）
//                    sb.append("         <RELCONTRACT>RELCONTRACT</RELCONTRACT>")     //相关合同编号
//                    sb.append("         <HAFHUSNA>HAFHUSNA</HAFHUSNA>")     //楼宇名称
//                    sb.append("         <OTHERDESC>OTHERDESC</OTHERDESC>")     //其他说明事项
                    mapinfo = ["全装修":"1","自装修":"2","整装修":"3","互联网装修":"4","其他":"5"]
                    sb.append("         <DECOREATETYPE>${mapinfo.get("整装修")}</DECOREATETYPE>")     //家装类型
                    sb.append("         <PROVINCEID>${house?.city?.province?.name}</PROVINCEID>")     //省份  TODO  HAAP系统维护
                    sb.append("         <CITYID>${house?.city?.name}</CITYID>")     //城市  TODO  HAAP系统维护
//                    sb.append("         <FBRANDID>FBRANDID</FBRANDID>")     //品牌   HAAP系统维护
//                    sb.append("         <CBRANDID>CBRANDID</CBRANDID>")     //系列   HAAP系统维护
//                    sb.append("         <AGENCYID>AGENCYID</AGENCYID>")     //经销商ID   HAAP系统维护
                    sb.append("     </RETAILINFO>")
                    sb.append("     <APPLYINFO>")     //申请信息
                    mapinfo = ["抵押":"01","信用":"02","质押":"03","担保":"04"]
                    sb.append("         <GRNT_FLAG>${mapinfo.get(opportunity?.guaranteeType?.name[0])}</GRNT_FLAG>")     //担保类型
                    mapinfo = ["否":"1","是":"2","":"9"]
                    sb.append("         <MTG_LN_FLAG>${mapinfo.get(opportunity?.collateralIsModified)}</MTG_LN_FLAG>")     //担保品修改标识  todo
                    sb.append("         <CARDEASYFLAG>N</CARDEASYFLAG>")     //POS刷卡放款  todo 未找到
//                    sb.append("         <OWNER>OWNER</OWNER>")     //业务营销柜员   todo
//                    sb.append("         <STATCODE>STATCODE</STATCODE>")     //统计编码
                    sb.append("         <LAFAPYAM>${opportunity?.ownFunds}</LAFAPYAM>")     //自有资金
                    sb.append("         <LOAN_AMOUNT>${opportunity?.loanAmount}</LOAN_AMOUNT>")     //分期金额
                    sb.append("         <LAFTERM>${opportunity?.loanDuration}</LAFTERM>")     //申请借款期限 （月）

                    sb.append("         <SXFSTAGE>${opportunity?.commissionPaymentMethod?.name == "一次性付"?"0":"1"}</SXFSTAGE>")     //手续费分期  todo  0-否，1-是
                    sb.append("         <LAFRATVL>${opportunity?.monthlyInterest}</LAFRATVL>")     //客户费率（%）
//                    sb.append("         <MCHT_CMSN>0</MCHT_CMSN>")     //贴息金额  todo
//                    sb.append("         <AGENCYRATE>AGENCYRATE</AGENCYRATE>")     //经销商贴息费率（%）
//                    sb.append("         <AGENCYGROUPRATE>AGENCYGROUPRATE</AGENCYGROUPRATE>")     //经销商集团贴息费率（%）
//                    sb.append("         <FACTORYRATE>FACTORYRATE</FACTORYRATE>")     //厂商贴息费率（%）
//                    sb.append("         <DISCOUNTID>DISCOUNTID</DISCOUNTID>")     //贴息方案编号
                    mapinfo = ["每月":"01","每季度":"03","每半年":"06","每年":"12"]
                    sb.append("         <RETPER>01</RETPER>")     //还款周期  todo
//                    sb.append("         <SIGNMINAMOUNT>SIGNMINAMOUNT</SIGNMINAMOUNT>")     //分期门槛金额 （元）
                    sb.append("         <FIRRET>20</FIRRET>")     //每期固定还款日  todo 未找到
                    sb.append("         <CARDNO>${bankAccount?.numberOfAccount?:0}</CARDNO>")     //信用卡卡号
                    sb.append("         <ISPEASANT>0</ISPEASANT>")     //是否农户贷款  todo 未找到
                    sb.append("         <RECEIVEPER>中国银行江西省分行</RECEIVEPER>")     //收款人
//                    sb.append("         <RECEIVEACCNO>RECEIVEACCNO</RECEIVEACCNO>")     //收款人账号
                    sb.append("         <APPLYDT>${opportunity?.createdDate?.format("YYYYMMDD")}</APPLYDT>")     //申请日期
                    sb.append("     </APPLYINFO>")
                }else if(opportunity?.product?.name == "汽车分期"){
                    def car = com.next.Vehicle.findByOpportunity(opportunity)
                    if (true){
                        sb.append("     <RETAILINFO>")     //交易信息
                        sb.append("         <WCIENGNO>${car?.engineCode}</WCIENGNO>")     //车辆发动机号
                        mapinfo = ["自用":"1","经营":"2"]
                        sb.append("         <LAFLNUSE>${mapinfo.get(car?.purpose)}</LAFLNUSE>")     //购车用途
                        mapinfo = ["国产":"1","进口":"2"]
                        sb.append("         <WCIADDR>${mapinfo.get(car?.purchaseSite)}</WCIADDR>")     //购车产地
                        mapinfo = ["乘用型":"1","商用型":"2"]
                        sb.append("         <WCICARTTY>${mapinfo.get(car?.marque)}</WCICARTTY>")     //贷款车型   todo 不确定
                        sb.append("         <WCISALECMP>${car?.distributorCustomerCode}</WCISALECMP>")     //经销商客户号
//                        sb.append("         <WCIINSNO>WCIINSNO</WCIINSNO>")     //零贷项目号
//                        sb.append("         <IMPORTNO>IMPORTNO</IMPORTNO>")     //进关单号
//                        sb.append("         <INSURE_CUNO>INSURE_CUNO</INSURE_CUNO>")     //保险公司客户号
//                        sb.append("         <WCIINSUR>WCIINSUR</WCIINSUR>")     //挂靠单位
                        sb.append("         <RELCONTRACT>${car?.vehicleLicense}</RELCONTRACT>")     //车牌号码
                        sb.append("         <WCIMOTNM>${car?.manufacturerVehicleMarque}</WCIMOTNM>")     //厂牌车型
                        sb.append("         <WCISHENO>${car?.carframeCode}</WCISHENO>")     //车架号码
                        sb.append("         <WCISCTNO>${car?.propertySerialNumber}</WCISCTNO>")     //购车合同号
                        sb.append("         <BRANDID>${car?.vehicleBrand}</BRANDID>")     //汽车品牌  todo 不确定
                        sb.append("         <CARTYPEID>${car?.vehicleSeries}</CARTYPEID>")     //汽车系列  todo 不确定
                        sb.append("         <CARMODELID>${car?.manufacturerVehicleMarque}</CARMODELID>")     //汽车车型  todo 不确定
                        sb.append("         <PROVINCEID>${car?.province?.name}</PROVINCEID>")     //省份  todo 不确定
                        sb.append("         <CITYID>${car?.city?.name}</CITYID>")     //城市  todo 不确定
                        sb.append("         <AGENCYID>${car?.distributorCustomerCode}</AGENCYID>")     //经销商ID  todo 不确定
                        sb.append("     </RETAILINFO>")
                        sb.append("     <APPLYINFO>")     //申请信息
//                        sb.append("         <OWNER>OWNER</OWNER>")     //业务营销柜员
//                        sb.append("         <STATCODE>STATCODE</STATCODE>")     //统计编码
                        sb.append("         <SXFSTAGE>${opportunity?.commissionPaymentMethod?.name == "一次性付"?"0":"1"}</SXFSTAGE>")     //手续费分期  todo
                        mapinfo = ["每月":"01","每季度":"03","每半年":"06","每年":"12"]
                        sb.append("         <RETPER>${mapinfo.get("每月")}</RETPER>")     //还款周期  todo
                        sb.append("         <FIRRET>20</FIRRET>")     //每期固定还款日
                        sb.append("         <APPLYDT>${opportunity?.createdDate?.format("YYYYMMDD")}</APPLYDT>")     //申请日期
                        sb.append("         <ISPEASANT>0</ISPEASANT>")     //是否农户贷款  todo  0-否，1-是
//                    sb.append("         <RECEIVEACCNO>RECEIVEACCNO</RECEIVEACCNO>")     //收款人账号
//                        sb.append("         <FINALPAYMENT>FINALPAYMENT</FINALPAYMENT>")     //尾款金额 （元）
                        sb.append("         <LOAN_AMOUNT>${opportunity?.loanAmount}</LOAN_AMOUNT>")     //分期金额
                        sb.append("         <LAFTERM>${opportunity?.loanDuration}</LAFTERM>")     //申请借款期限 （月）
                        sb.append("         <LAFRATVL>${opportunity?.monthlyInterest}</LAFRATVL>")     //客户费率（%）
//                    sb.append("         <MCHT_CMSN>0</MCHT_CMSN>")     //贴息金额  todo
//                    sb.append("         <AGENCYRATE>AGENCYRATE</AGENCYRATE>")     //经销商贴息费率（%）
//                    sb.append("         <AGENCYGROUPRATE>AGENCYGROUPRATE</AGENCYGROUPRATE>")     //经销商集团贴息费率（%）
//                    sb.append("         <FACTORYRATE>FACTORYRATE</FACTORYRATE>")     //厂商贴息费率（%）
//                    sb.append("         <DISCOUNTID>DISCOUNTID</DISCOUNTID>")     //贴息方案编号
                        sb.append("         <CARDNO>${bankAccount?.numberOfAccount?:0}</CARDNO>")     //信用卡卡号
                        sb.append("         <RECEIVEPER>中国银行江西省分行</RECEIVEPER>")     //收款人 todo  未找到
                        sb.append("         <LAFAPYAM>${opportunity?.ownFunds}</LAFAPYAM>")     //自有资金
                        mapinfo = ["抵押":"01","信用":"02","质押":"03","担保":"04"]
                        sb.append("         <GRNT_FLAG>${mapinfo.get(opportunity?.guaranteeType?.name[0])}</GRNT_FLAG>")     //担保类型
                        mapinfo = ["否":"1","是":"2","":"9"]
                        sb.append("         <MTG_LN_FLAG>${mapinfo.get(opportunity?.collateralIsModified)}</MTG_LN_FLAG>")     //担保品修改标识  TODO
                        sb.append("         <IS_FLEX_REPYMT>N</IS_FLEX_REPYMT>")     //是否灵活还款 todo N-否，Y-是
//                        sb.append("         <FLEX_REPYMT_CODE>FLEX_REPYMT_CODE</FLEX_REPYMT_CODE>")     //灵活还款方式  todo 灵活还款为是时，必输
                        sb.append("         <IS_AUT_PORSCHE>N</IS_AUT_PORSCHE>")     //客户是否授权信息送保时捷   todo N-否，Y-是  品牌为148-保时捷时必输
                        sb.append("         <RAMI_AMOUNT>0</RAMI_AMOUNT>")     //衍生分期金额  TODO
                        sb.append("         <PLJJ_GRNT_FLAG>${mapinfo.get(opportunity?.guaranteeType?.name[0])}</PLJJ_GRNT_FLAG>")     //衍生分期担保类型

                        sb.append("         <PLJJ_MTG_LN_FLAG>9</PLJJ_MTG_LN_FLAG>")     //衍生分期担保品修改标识  TODO
//                        sb.append("         <PLJJ_OWNER>PLJJ_OWNER</PLJJ_OWNER>")     //衍生分期业务营销柜员
//                        sb.append("         <PLJJ_STATCODE>PLJJ_STATCODE</PLJJ_STATCODE>")     //衍生分期统计编码
                        sb.append("         <PLJJ_LAFAPYAM>${opportunity?.ownFunds}</PLJJ_LAFAPYAM>")     //衍生分期自有资金
                        sb.append("         <PLJJ_LAFTERM>${opportunity?.loanDuration}</PLJJ_LAFTERM>")     //衍生分期申请借款期限 （月）
                        sb.append("         <PLJJ_SXFSTAGE>${opportunity?.commissionPaymentMethod?.name == "一次性付"?"0":"1"}</PLJJ_SXFSTAGE>")     //衍生分期手续费分期 todo  0-否，1-是
                        sb.append("         <PLJJ_RETPER>01</PLJJ_RETPER>")     //衍生分期还款周期
                        sb.append("         <PLJJ_FIRRET>20</PLJJ_FIRRET>")     //衍生分期每期固定还款日
                        sb.append("         <PLJJ_CARDNO>${bankAccount?.numberOfAccount?:0}</PLJJ_CARDNO>")     //衍生分期信用卡卡号
                        sb.append("         <PLJJ_APPLYDT>${opportunity?.createdDate?.format("YYYYMMDD")}</PLJJ_APPLYDT>")     //衍生分期申请日期
                        sb.append("         <PLJJ_ISPEASANT>0</PLJJ_ISPEASANT>")     //衍生分期是否农户贷款 todo  0-否，1-是  未找到
                        sb.append("         <PLJJ_RECEIVEPER>中国银行江西省分行</PLJJ_RECEIVEPER>")     //衍生分期收款人 todo
//                        sb.append("         <PLJJ_RECEIVEACCNO>PLJJ_RECEIVEACCNO</PLJJ_RECEIVEACCNO>")     //衍生分期收款人账号
//                        sb.append("         <PLJJ_LAFRATVL>PLJJ_LAFRATVL</PLJJ_LAFRATVL>")     //衍生分期客户承担手续费率 （%）
//                        sb.append("         <PLJJ_MCHT_LAFRATVL>PLJJ_MCHT_LAFRATVL</PLJJ_MCHT_LAFRATVL>")     //衍生分期合作方承担手续费率 （%）
//                        sb.append("         <RAMI_AMOUNT_BX>RAMI_AMOUNT_BX</RAMI_AMOUNT_BX>")     //汽车衍生消费（保险）金额
//                        sb.append("         <RAMI_LAFRATVL_BX>RAMI_LAFRATVL_BX</RAMI_LAFRATVL_BX>")     //汽车衍生消费（保险）手续费率(%)
//                        sb.append("         <RAMI_MCHT_LAFRATVL_BX>RAMI_MCHT_LAFRATVL_BX</RAMI_MCHT_LAFRATVL_BX>")     //汽车衍生消费（保险）合作方补贴比率(%)
//                        sb.append("         <RAMI_AMOUNT_JPZH>RAMI_AMOUNT_JPZH</RAMI_AMOUNT_JPZH>")     //汽车衍生消费（精品装潢）金额
//                        sb.append("         <RAMI_LAFRATVL_JPZH>RAMI_LAFRATVL_JPZH</RAMI_LAFRATVL_JPZH>")     //汽车衍生消费（精品装潢）手续费率(%)
//                        sb.append("         <RAMI_MCHT_LAFRATVL_JPZH>RAMI_MCHT_LAFRATVL_JPZH</RAMI_MCHT_LAFRATVL_JPZH>")     //汽车衍生消费（精品装潢）合作方补贴比率(%)
//                        sb.append("         <RAMI_AMOUNT_GZS>RAMI_AMOUNT_GZS</RAMI_AMOUNT_GZS>")     //汽车衍生消费（购置税）金额
//                        sb.append("         <RAMI_LAFRATVL_GZS>RAMI_LAFRATVL_GZS</RAMI_LAFRATVL_GZS>")     //汽车衍生消费（购置税）手续费率(%)
//                        sb.append("         <RAMI_MCHT_LAFRATVL_GZS>RAMI_MCHT_LAFRATVL_GZS</RAMI_MCHT_LAFRATVL_GZS>")     //汽车衍生消费（购置税）合作方补贴比率(%)
//                        sb.append("         <RAMI_AMOUNT_WX>RAMI_AMOUNT_WX</RAMI_AMOUNT_WX>")     //汽车衍生消费（维修）金额
//                        sb.append("         <RAMI_LAFRATVL_WX>RAMI_LAFRATVL_WX</RAMI_LAFRATVL_WX>")     //汽车衍生消费（维修）手续费率(%)
//                        sb.append("         <RAMI_MCHT_LAFRATVL_WX>RAMI_MCHT_LAFRATVL_WX</RAMI_MCHT_LAFRATVL_WX>")     //汽车衍生消费（维修）合作方补贴比率(%)
//                        sb.append("         <RAMI_AMOUNT_BY>RAMI_AMOUNT_BY</RAMI_AMOUNT_BY>")     //汽车衍生消费（保养）金额
//                        sb.append("         <RAMI_LAFRATVL_BY>RAMI_LAFRATVL_BY</RAMI_LAFRATVL_BY>")     //汽车衍生消费（保养）手续费率(%)
//                        sb.append("         <RAMI_MCHT_LAFRATVL_BY>RAMI_MCHT_LAFRATVL_BY</RAMI_MCHT_LAFRATVL_BY>")     //汽车衍生消费（保养）合作方补贴比率(%)
//                        sb.append("         <RAMI_AMOUNT_YB>RAMI_AMOUNT_YB</RAMI_AMOUNT_YB>")     //汽车衍生消费（延保）金额
//                        sb.append("         <RAMI_LAFRATVL_YB>RAMI_LAFRATVL_YB</RAMI_LAFRATVL_YB>")     //汽车衍生消费（延保）手续费率(%)
//                        sb.append("         <RAMI_MCHT_LAFRATVL_YB>RAMI_MCHT_LAFRATVL_YB</RAMI_MCHT_LAFRATVL_YB>")     //汽车衍生消费（延保）合作方补贴比率(%)
//                        sb.append("         <RAMI_AMOUNT_CP>RAMI_AMOUNT_CP</RAMI_AMOUNT_CP>")     //汽车衍生消费（车牌）金额
//                        sb.append("         <RAMI_LAFRATVL_CP>RAMI_LAFRATVL_CP</RAMI_LAFRATVL_CP>")     //汽车衍生消费（车牌）手续费率(%)
//                        sb.append("         <RAMI_MCHT_LAFRATVL_CP>RAMI_MCHT_LAFRATVL_CP</RAMI_MCHT_LAFRATVL_CP>")     //汽车衍生消费（车牌）合作方补贴比率(%)
//                        sb.append("         <RAMI_AMOUNT_BJ>RAMI_AMOUNT_BJ</RAMI_AMOUNT_BJ>")     //汽车衍生消费（备件）金额
//                        sb.append("         <RAMI_LAFRATVL_BJ>RAMI_LAFRATVL_BJ</RAMI_LAFRATVL_BJ>")     //汽车衍生消费（备件）手续费率(%)
//                        sb.append("         <RAMI_MCHT_LAFRATVL_BJ>RAMI_MCHT_LAFRATVL_BJ</RAMI_MCHT_LAFRATVL_BJ>")     //汽车衍生消费（备件）合作方补贴比率(%)
//                        sb.append("         <RAMI_AMOUNT_QT>RAMI_AMOUNT_QT</RAMI_AMOUNT_QT>")     //汽车衍生消费（其他）金额
//                        sb.append("         <RAMI_LAFRATVL_QT>RAMI_LAFRATVL_QT</RAMI_LAFRATVL_QT>")     //汽车衍生消费（其他）手续费率(%)
//                        sb.append("         <RAMI_MCHT_LAFRATVL_QT>RAMI_MCHT_LAFRATVL_QT</RAMI_MCHT_LAFRATVL_QT>")     //汽车衍生消费（其他）合作方补贴比率(%)
//                        sb.append("         <RAMI_AMOUNT_QT2>RAMI_AMOUNT_QT2</RAMI_AMOUNT_QT2>")     //汽车衍生消费（其他2）金额
//                        sb.append("         <RAMI_LAFRATVL_QT2>RAMI_LAFRATVL_QT2</RAMI_LAFRATVL_QT2>")     //汽车衍生消费（其他2）手续费率(%)
//                        sb.append("         <RAMI_MCHT_LAFRATVL_QT2>RAMI_MCHT_LAFRATVL_QT2</RAMI_MCHT_LAFRATVL_QT2>")     //汽车衍生消费（其他2）合作方补贴比率(%)
//                        sb.append("         <RAMI_AMOUNT_QT3>RAMI_AMOUNT_QT3</RAMI_AMOUNT_QT3>")     //汽车衍生消费（其他3）金额
//                        sb.append("         <RAMI_LAFRATVL_QT3>RAMI_LAFRATVL_QT3</RAMI_LAFRATVL_QT3>")     //汽车衍生消费（其他3）手续费率(%)
//                        sb.append("         <RAMI_MCHT_LAFRATVL_QT3>RAMI_MCHT_LAFRATVL_QT3</RAMI_MCHT_LAFRATVL_QT3>")     //汽车衍生消费（其他3）合作方补贴比率(%)
                        sb.append("     </APPLYINFO>")
                    }else if(false){
                        sb.append("     <RETAILINFO>")     //交易信息
                        sb.append("         <WCIENGNO>${car?.engineCode}</WCIENGNO>")     //车辆发动机号
                        mapinfo = ["自用":"1","经营":"2"]
                        sb.append("         <LAFLNUSE>${mapinfo.get(car?.purpose)}</LAFLNUSE>")     //购车用途
                        mapinfo = ["国产":"1","进口":"2"]
                        sb.append("         <WCIADDR>${mapinfo.get(car?.purchaseSite)}</WCIADDR>")     //购车产地
                        mapinfo = ["乘用型":"1","商用型":"2"]
                        sb.append("         <WCICARTTY>${mapinfo.get(car?.marque)}</WCICARTTY>")     //贷款车型   todo 不确定
                        sb.append("         <WCISALECMP>${car?.distributorCustomerCode}</WCISALECMP>")     //经销商客户号
//                        sb.append("         <WCIINSNO>WCIINSNO</WCIINSNO>")     //零贷项目号
//                        sb.append("         <IMPORTNO>IMPORTNO</IMPORTNO>")     //进关单号
//                        sb.append("         <INSURE_CUNO>INSURE_CUNO</INSURE_CUNO>")     //保险公司客户号
//                        sb.append("         <WCIINSUR>WCIINSUR</WCIINSUR>")     //挂靠单位
                        sb.append("         <RELCONTRACT>${car?.vehicleLicense}</RELCONTRACT>")     //车牌号码
                        sb.append("         <WCIMOTNM>${car?.manufacturerVehicleMarque}</WCIMOTNM>")     //厂牌车型
                        sb.append("         <WCISHENO>${car?.carframeCode}</WCISHENO>")     //车架号码
                        sb.append("         <WCISCTNO>${car?.propertySerialNumber}</WCISCTNO>")     //购车合同号
                        sb.append("         <BRANDID>${car?.vehicleBrand}</BRANDID>")     //汽车品牌  todo 不确定
                        sb.append("         <CARTYPEID>${car?.vehicleSeries}</CARTYPEID>")     //汽车系列  todo 不确定
                        sb.append("         <CARMODELID>${car?.manufacturerVehicleMarque}</CARMODELID>")     //汽车车型  todo 不确定
                        sb.append("         <PROVINCEID>${car?.province?.name}</PROVINCEID>")     //省份  todo 不确定
                        sb.append("         <CITYID>${car?.city?.name}</CITYID>")     //城市  todo 不确定
                        sb.append("         <AGENCYID>${car?.distributorCustomerCode}</AGENCYID>")     //经销商ID  todo 不确定
                        sb.append("     </RETAILINFO>")
                        sb.append("     <APPLYINFO>")     //申请信息
//                        sb.append("         <OWNER>OWNER</OWNER>")     //业务营销柜员
//                        sb.append("         <STATCODE>STATCODE</STATCODE>")     //统计编码
                        sb.append("         <SXFSTAGE>${opportunity?.commissionPaymentMethod?.name == "一次性付"?"0":"1"}</SXFSTAGE>")     //手续费分期  todo
                        mapinfo = ["每月":"01","每季度":"03","每半年":"06","每年":"12"]
                        sb.append("         <RETPER>${mapinfo.get("每月")}</RETPER>")     //还款周期  todo
                        sb.append("         <FIRRET>20</FIRRET>")     //每期固定还款日
                        sb.append("         <APPLYDT>${opportunity?.createdDate?.format("YYYYMMDD")}</APPLYDT>")     //申请日期
                        sb.append("         <ISPEASANT>0</ISPEASANT>")     //是否农户贷款  todo
//                    sb.append("         <RECEIVEACCNO>RECEIVEACCNO</RECEIVEACCNO>")     //收款人账号
//                        sb.append("         <FINALPAYMENT>FINALPAYMENT</FINALPAYMENT>")     //尾款金额 （元）
                        sb.append("         <LOAN_AMOUNT>${opportunity?.loanAmount}</LOAN_AMOUNT>")     //分期金额
                        sb.append("         <LAFTERM>${opportunity?.loanDuration}</LAFTERM>")     //申请借款期限 （月）
                        sb.append("         <LAFRATVL>${opportunity?.monthlyInterest}</LAFRATVL>")     //客户费率（%）
//                    sb.append("         <MCHT_CMSN>0</MCHT_CMSN>")     //贴息金额  todo
//                    sb.append("         <AGENCYRATE>AGENCYRATE</AGENCYRATE>")     //经销商贴息费率（%）
//                    sb.append("         <AGENCYGROUPRATE>AGENCYGROUPRATE</AGENCYGROUPRATE>")     //经销商集团贴息费率（%）
//                    sb.append("         <FACTORYRATE>FACTORYRATE</FACTORYRATE>")     //厂商贴息费率（%）
//                    sb.append("         <DISCOUNTID>DISCOUNTID</DISCOUNTID>")     //贴息方案编号
                        sb.append("         <CARDNO>${bankAccount?.numberOfAccount?:0}</CARDNO>")     //信用卡卡号
                        sb.append("         <RECEIVEPER>中国银行江西省分行</RECEIVEPER>")     //收款人
                        sb.append("         <LAFAPYAM>${opportunity?.ownFunds}</LAFAPYAM>")     //自有资金
                        mapinfo = ["抵押":"01","信用":"02","质押":"03","担保":"04"]
                        sb.append("         <GRNT_FLAG>${mapinfo.get(opportunity?.guaranteeType?.name[0])}</GRNT_FLAG>")     //担保类型
                        mapinfo = ["否":"1","是":"2","":"9"]
                        sb.append("         <MTG_LN_FLAG>${mapinfo.get(opportunity?.collateralIsModified)}</MTG_LN_FLAG>")     //担保品修改标识  TODO
                        sb.append("         <IS_FLEX_REPYMT>N</IS_FLEX_REPYMT>")     //是否灵活还款 todo N-否，Y-是
//                        sb.append("         <FLEX_REPYMT_CODE>FLEX_REPYMT_CODE</FLEX_REPYMT_CODE>")     //灵活还款方式  todo 灵活还款为是时，必输
                        sb.append("         <IS_AUT_PORSCHE>N</IS_AUT_PORSCHE>")     //客户是否授权信息送保时捷   todo N-否，Y-是  品牌为148-保时捷时必输
                        sb.append("         <RAMI_AMOUNT>${opportunity?.loanAmount}</RAMI_AMOUNT>")     //衍生分期金额  TODO  不确定
                        sb.append("     </APPLYINFO>")
                    }else if(1==1){
                        //交易信息-汽车衍生分期字段报文
                        sb.append("     <RETAILINFO>")     //交易信息
                        sb.append("         <WCIENGNO>${car?.engineCode}</WCIENGNO>")     //车辆发动机号
                        mapinfo = ["自用":"1","经营":"2"]
                        sb.append("         <LAFLNUSE>${mapinfo.get(car?.purpose)}</LAFLNUSE>")     //购车用途
                        mapinfo = ["国产":"1","进口":"2"]
                        sb.append("         <WCIADDR>${mapinfo.get(car?.purchaseSite)}</WCIADDR>")     //购车产地
                        mapinfo = ["乘用型":"1","商用型":"2"]
                        sb.append("         <WCICARTTY>${mapinfo.get(car?.marque)}</WCICARTTY>")     //贷款车型   todo 不确定
                        sb.append("         <WCISALECMP>${car?.distributorCustomerCode}</WCISALECMP>")     //经销商客户号
//                        sb.append("         <WCIINSNO>WCIINSNO</WCIINSNO>")     //零贷项目号
//                        sb.append("         <IMPORTNO>IMPORTNO</IMPORTNO>")     //进关单号
//                        sb.append("         <INSURE_CUNO>INSURE_CUNO</INSURE_CUNO>")     //保险公司客户号
//                        sb.append("         <WCIINSUR>WCIINSUR</WCIINSUR>")     //挂靠单位
                        sb.append("         <RELCONTRACT>${car?.vehicleLicense}</RELCONTRACT>")     //车牌号码
                        sb.append("         <WCIMOTNM>${car?.manufacturerVehicleMarque}</WCIMOTNM>")     //厂牌车型
                        sb.append("         <WCISHENO>${car?.carframeCode}</WCISHENO>")     //车架号码
                        sb.append("         <WCISCTNO>${car?.propertySerialNumber}</WCISCTNO>")     //购车合同号
                        sb.append("         <BRANDID>${car?.vehicleBrand}</BRANDID>")     //汽车品牌  todo  不确定
                        sb.append("         <CARTYPEID>${car?.vehicleSeries}</CARTYPEID>")     //汽车系列  todo  不确定
                        sb.append("         <CARMODELID>${car?.manufacturerVehicleMarque}</CARMODELID>")     //汽车车型  todo  不确定
                        sb.append("         <PROVINCEID>${car?.province?.name}</PROVINCEID>")     //省份  todo  不确定
                        sb.append("         <CITYID>${car?.city?.name}</CITYID>")     //城市  todo  不确定
                        sb.append("         <AGENCYID>${car?.distributorCustomerCode}</AGENCYID>")     //经销商ID  todo  不确定
                        sb.append("     </RETAILINFO>")
                        sb.append("     <APPLYINFO>")     //申请信息
                        mapinfo = ["抵押":"01","信用":"02","质押":"03","担保":"04"]
                        sb.append("         <GRNT_FLAG>${mapinfo.get(opportunity?.guaranteeType?.name[0])}</GRNT_FLAG>")     //担保类型
                        sb.append("         <MTG_LN_FLAG>9</MTG_LN_FLAG>")     //担保品修改标识  TODO
//                        sb.append("         <OWNER>OWNER</OWNER>")     //业务营销柜员
//                        sb.append("         <STATCODE>STATCODE</STATCODE>")     //统计编码
                        sb.append("         <LAFAPYAM>${opportunity?.ownFunds}</LAFAPYAM>")     //自有资金
                        sb.append("         <LAFTERM>${opportunity?.loanDuration}</LAFTERM>")     //申请借款期限 （月）
                        sb.append("         <SXFSTAGE>${opportunity?.commissionPaymentMethod?.name == "一次性付"?"0":"1"}</SXFSTAGE>")     //手续费分期  todo
                        mapinfo = ["每月":"01","每季度":"03","每半年":"06","每年":"12"]
                        sb.append("         <RETPER>${mapinfo.get("每月")}</RETPER>")     //还款周期  todo
                        sb.append("         <FIRRET>20</FIRRET>")     //每期固定还款日
                        sb.append("         <CARDNO>${bankAccount?.numberOfAccount?:0}</CARDNO>")     //信用卡卡号
                        sb.append("         <ISPEASANT>0</ISPEASANT>")     //是否农户贷款  todo  未找到
                        sb.append("         <RECEIVEPER>中国银行江西省分行</RECEIVEPER>")     //收款人
//                        sb.append("         <RECEIVEACCNO>RECEIVEACCNO</RECEIVEACCNO>")     //收款人账号
                        sb.append("         <APPLYDT>${opportunity?.createdDate?.format("YYYYMMDD")}</APPLYDT>")     //申请日期
//                        sb.append("         <LAFRATVL>LAFRATVL</LAFRATVL>")     //客户承担手续费率 （%）
//                        sb.append("         <MCHT_LAFRATVL>MCHT_LAFRATVL</MCHT_LAFRATVL>")     //合作方承担手续费率 （%）
//                        sb.append("         <RAMI_AMOUNT_BX>RAMI_AMOUNT_BX</RAMI_AMOUNT_BX>")     //汽车衍生消费（保险）金额
//                        sb.append("         <RAMI_LAFRATVL_BX>RAMI_LAFRATVL_BX</RAMI_LAFRATVL_BX>")     //汽车衍生消费（保险）手续费率(%)
//                        sb.append("         <RAMI_MCHT_LAFRATVL_BX>RAMI_MCHT_LAFRATVL_BX</RAMI_MCHT_LAFRATVL_BX>")     //汽车衍生消费（保险）合作方补贴比率(%)
//                        sb.append("         <RAMI_AMOUNT_JPZH>RAMI_AMOUNT_JPZH</RAMI_AMOUNT_JPZH>")     //汽车衍生消费（精品装潢）金额
//                        sb.append("         <RAMI_LAFRATVL_JPZH>RAMI_LAFRATVL_JPZH</RAMI_LAFRATVL_JPZH>")     //汽车衍生消费（精品装潢）手续费率(%)
//                        sb.append("         <RAMI_MCHT_LAFRATVL_JPZH>RAMI_MCHT_LAFRATVL_JPZH</RAMI_MCHT_LAFRATVL_JPZH>")     //汽车衍生消费（精品装潢）合作方补贴比率(%)
//                        sb.append("         <RAMI_AMOUNT_GZS>RAMI_AMOUNT_GZS</RAMI_AMOUNT_GZS>")     //汽车衍生消费（购置税）金额
//                        sb.append("         <RAMI_LAFRATVL_GZS>RAMI_LAFRATVL_GZS</RAMI_LAFRATVL_GZS>")     //汽车衍生消费（购置税）手续费率(%)
//                        sb.append("         <RAMI_MCHT_LAFRATVL_GZS>RAMI_MCHT_LAFRATVL_GZS</RAMI_MCHT_LAFRATVL_GZS>")     //汽车衍生消费（购置税）合作方补贴比率(%)
//                        sb.append("         <RAMI_AMOUNT_WX>RAMI_AMOUNT_WX</RAMI_AMOUNT_WX>")     //汽车衍生消费（维修）金额
//                        sb.append("         <RAMI_LAFRATVL_WX>RAMI_LAFRATVL_WX</RAMI_LAFRATVL_WX>")     //汽车衍生消费（维修）手续费率(%)
//                        sb.append("         <RAMI_MCHT_LAFRATVL_WX>RAMI_MCHT_LAFRATVL_WX</RAMI_MCHT_LAFRATVL_WX>")     //汽车衍生消费（维修）合作方补贴比率(%)
//                        sb.append("         <RAMI_AMOUNT_BY>RAMI_AMOUNT_BY</RAMI_AMOUNT_BY>")     //汽车衍生消费（保养）金额
//                        sb.append("         <RAMI_LAFRATVL_BY>RAMI_LAFRATVL_BY</RAMI_LAFRATVL_BY>")     //汽车衍生消费（保养）手续费率(%)
//                        sb.append("         <RAMI_MCHT_LAFRATVL_BY>RAMI_MCHT_LAFRATVL_BY</RAMI_MCHT_LAFRATVL_BY>")     //汽车衍生消费（保养）合作方补贴比率(%)
//                        sb.append("         <RAMI_AMOUNT_YB>RAMI_AMOUNT_YB</RAMI_AMOUNT_YB>")     //汽车衍生消费（延保）金额
//                        sb.append("         <RAMI_LAFRATVL_YB>RAMI_LAFRATVL_YB</RAMI_LAFRATVL_YB>")     //汽车衍生消费（延保）手续费率(%)
//                        sb.append("         <RAMI_MCHT_LAFRATVL_YB>RAMI_MCHT_LAFRATVL_YB</RAMI_MCHT_LAFRATVL_YB>")     //汽车衍生消费（延保）合作方补贴比率(%)
//                        sb.append("         <RAMI_AMOUNT_CP>RAMI_AMOUNT_CP</RAMI_AMOUNT_CP>")     //汽车衍生消费（车牌）金额
//                        sb.append("         <RAMI_LAFRATVL_CP>RAMI_LAFRATVL_CP</RAMI_LAFRATVL_CP>")     //汽车衍生消费（车牌）手续费率(%)
//                        sb.append("         <RAMI_MCHT_LAFRATVL_CP>RAMI_MCHT_LAFRATVL_CP</RAMI_MCHT_LAFRATVL_CP>")     //汽车衍生消费（车牌）合作方补贴比率(%)
//                        sb.append("         <RAMI_AMOUNT_BJ>RAMI_AMOUNT_BJ</RAMI_AMOUNT_BJ>")     //汽车衍生消费（备件）金额
//                        sb.append("         <RAMI_LAFRATVL_BJ>RAMI_LAFRATVL_BJ</RAMI_LAFRATVL_BJ>")     //汽车衍生消费（备件）手续费率(%)
//                        sb.append("         <RAMI_MCHT_LAFRATVL_BJ>RAMI_MCHT_LAFRATVL_BJ</RAMI_MCHT_LAFRATVL_BJ>")     //汽车衍生消费（备件）合作方补贴比率(%)
//                        sb.append("         <RAMI_AMOUNT_QT>RAMI_AMOUNT_QT</RAMI_AMOUNT_QT>")     //汽车衍生消费（其他）金额
//                        sb.append("         <RAMI_LAFRATVL_QT>RAMI_LAFRATVL_QT</RAMI_LAFRATVL_QT>")     //汽车衍生消费（其他）手续费率(%)
//                        sb.append("         <RAMI_MCHT_LAFRATVL_QT>RAMI_MCHT_LAFRATVL_QT</RAMI_MCHT_LAFRATVL_QT>")     //汽车衍生消费（其他）合作方补贴比率(%)
//                        sb.append("         <RAMI_AMOUNT_QT2>RAMI_AMOUNT_QT2</RAMI_AMOUNT_QT2>")     //汽车衍生消费（其他2）金额
//                        sb.append("         <RAMI_LAFRATVL_QT2>RAMI_LAFRATVL_QT2</RAMI_LAFRATVL_QT2>")     //汽车衍生消费（其他2）手续费率(%)
//                        sb.append("         <RAMI_MCHT_LAFRATVL_QT2>RAMI_MCHT_LAFRATVL_QT2</RAMI_MCHT_LAFRATVL_QT2>")     //汽车衍生消费（其他2）合作方补贴比率(%)
//                        sb.append("         <RAMI_AMOUNT_QT3>RAMI_AMOUNT_QT3</RAMI_AMOUNT_QT3>")     //汽车衍生消费（其他3）金额
//                        sb.append("         <RAMI_LAFRATVL_QT3>RAMI_LAFRATVL_QT3</RAMI_LAFRATVL_QT3>")     //汽车衍生消费（其他3）手续费率(%)
//                        sb.append("         <RAMI_MCHT_LAFRATVL_QT3>RAMI_MCHT_LAFRATVL_QT3</RAMI_MCHT_LAFRATVL_QT3>")     //汽车衍生消费（其他3）合作方补贴比率(%)
                        sb.append("     </APPLYINFO>")     //报文类型
                    }else{
                        return null
                    }
                }else{
                    return null
                }
                sb.append(" </BODY>")
                sb.append("</MSG>")
                return String.format("%05d", sb.toString().length()) + sb.toString()
            }
            def sentHTTPRequest = { urlString, requestData, String header ->
                try
                {
                    def connection = (java.net.HttpURLConnection) urlString.openConnection()
                    connection.setDoOutput(true)
                    connection.setRequestMethod("POST")
                    connection.setRequestProperty("Content-Type", header)
                    connection.outputStream.withWriter("UTF-8") { java.io.Writer writer -> writer.write requestData }
                    connection.setConnectTimeout(60000)
                    result = grails.converters.JSON.parse(connection.inputStream.withReader("UTF-8") { java.io.Reader reader -> reader.text })
                    return result
                }
                catch (java.lang.Exception e)
                {
                    e.printStackTrace()
                    println(e)
                }
            }
            //R系统报文组织
            map = [:]
            map.code = dataMap.verifiedCode
            map.cellphone = dataMap.cellphone
            def data = getXmlInfo(map)
            println "发送R系统报文："+data
            if (data){
                result = sentHTTPRequest(new java.net.URL("http://127.0.0.1:8089/RLMS/v1/sendMessage.action"), groovy.json.JsonOutput.toJson(map).toString(), "application/json")
                println "发送R系统信息返回结果：" + result
                if (result?.stateCode == "00000")
                {
                    println(["message": "发送R系统数据成功", "status": "成功"] as grails.converters.JSON)
                    return true
                }
                else
                {
                    println(["message": "发送R系统返回失败", "status": "失败"] as grails.converters.JSON)
                    return true
                }
            }else{
                println(["message": "订单类型错误", "status": "失败"] as grails.converters.JSON)
                return true
            }
        }
        else
        {
            println(["message": "获取不到订单", "status": "失败"] as grails.converters.JSON)
            return true
        }
    }

    /** @Description RLCOL104接口报文
     * @Params
     * @Return xml
     * @Author wangc
     * @Datetime 2019/2/26 002615:12
     */
    def RLCOL104 = { dataMap ->
        def result
        def map
        com.next.Opportunity opportunity = dataMap.opportunity
        if(opportunity){
            def getXmlInfo = { map1 ->
                StringBuilder sb = new StringBuilder()
                sb.append("<?xml version='1.0' encoding='utf-8'?> standalone='yes'")
                sb.append("<MSG>")
                sb.append(" <HEAD>")
                sb.append("     <MSGTYPE>0100</MSGTYPE>")     //报文类型
                sb.append("     <CUSTYPE>01</CUSTYPE>")     //客户类型
                sb.append("     <TRAN_CODE>RLCOL104</TRAN_CODE>")     //交易码
                sb.append("     <LAUNCHERID>015</LAUNCHERID>")     //发起方标志
                sb.append("     <PLATID>015</PLATID>")     //平台号
                sb.append("     <REQUEST_DATE>${new java.util.Date().format('YYYYMMDD')}</REQUEST_DATE>")     //交易请求日期
                sb.append("     <REQUEST_TIME>${new java.util.Date().format('HHmmss')}</REQUEST_TIME>")     //交易请求事件
                sb.append("     <RESSYSTEM_ID>015</RESSYSTEM_ID>")     //响应方标志
//                sb.append("     <RESPOND_DATE>RESPOND_DATE</RESPOND_DATE>")     //交易响应日期
//                sb.append("     <RESPOND_TIME>RESPOND_TIME</RESPOND_TIME>")     //交易响应时间
                sb.append("     <REQ_TRACENO>${java.util.UUID.randomUUID().toString()}</REQ_TRACENO>")     //UUID 请求方必填
//                sb.append("     <RES_TRACENO>RES_TRACENO</RES_TRACENO>")     //UUID 响应方系统必填
//                sb.append("     <RETCODE>RETCODE</RETCODE>")     //交易结果返回码
//                sb.append("     <ERRORMSG>ERRORMSG</ERRORMSG>")     //错误原因
//                sb.append("     <SIGNATURE>SIGNATURE</SIGNATURE>")     //签名
//                sb.append("     <RESERVE_FIELD>RESERVE_FIELD</RESERVE_FIELD>")     //备用域
                sb.append(" </HEAD>")
                sb.append(" <BODY>")
                sb.append("     <TASK_SEQNO>${opportunity?.serialNumber}</TASK_SEQNO>")     //流水号
                def scope = ["全部(包括已删除及未删除)":"0","未删除":"1","已删除":"2"]
                sb.append("     <SCOPE>${scope.get("全部(包括已删除及未删除)")}</SCOPE>")     //查询范围   todo
                def querytype = ["全部（包括线下发起申请和在线场景分期）":"00","在线场景分期":"01"]
                sb.append("     <QUERY_TYPE>${querytype?.get("全部（包括线下发起申请和在线场景分期）")}</TYPE>")     //查询类型  todo
                sb.append(" </BODY>")
                sb.append("</MSG>")
                return String.format("%05d", sb.toString().length()) + sb.toString()
            }
            def sentHTTPRequest = { urlString, requestData, String header ->
                try
                {
                    def connection = (java.net.HttpURLConnection) urlString.openConnection()
                    connection.setDoOutput(true)
                    connection.setRequestMethod("POST")
                    connection.setRequestProperty("Content-Type", header)
                    connection.outputStream.withWriter("UTF-8") { java.io.Writer writer -> writer.write requestData }
                    connection.setConnectTimeout(60000)
                    result = grails.converters.JSON.parse(connection.inputStream.withReader("UTF-8") { java.io.Reader reader -> reader.text })
                    return result
                }
                catch (java.lang.Exception e)
                {
                    e.printStackTrace()
                    println(e)
                }
            }
            //获取token请求参数
            map = [:]
            map.code = dataMap.verifiedCode
            map.cellphone = dataMap.cellphone
            def data = getXmlInfo(map)
            println "RLCOL104发送R系统报文："+data
            if (data){
                result = sentHTTPRequest(new java.net.URL("http://5q6zif.natappfree.cc/decision/sync/get"), groovy.json.JsonOutput.toJson(map).toString(), "application/json")
                println "RLCOL104发送R系统信息返回结果：" + result
                if (result?.stateCode == "00000")
                {
                    println(["message": "RLCOL104发送R系统数据成功", "status": "成功"] as grails.converters.JSON)
                    return true
                }
                else
                {
                    println(["message": "RLCOL104发送R系统返回失败", "status": "失败"] as grails.converters.JSON)
                    return true
                }
            }else{
                println(["message": "RLCOL104订单类型错误", "status": "失败"] as grails.converters.JSON)
                return true
            }
        }
        else
        {
            println(["message": "RLCOL104获取不到订单", "status": "失败"] as grails.converters.JSON)
            return true
        }
    }

    /** @Description RLCOL105接口报文
     * @Params
     * @Return xml
     * @Author wangc
     * @Datetime 2019/2/26 002615:12
     */
    def RLCOL105 = { dataMap ->
        def result
        def map
        com.next.Opportunity opportunity = dataMap.opportunity
        com.next.Contact contact = opportunity?.contact
        if(opportunity){
            def getXmlInfo = { map1 ->
                StringBuilder sb = new StringBuilder()
                sb.append("<?xml version='1.0' encoding='utf-8'?> standalone='yes'")
                sb.append("<MSG>")
                sb.append(" <HEAD>")
                sb.append("     <MSGTYPE>0100</MSGTYPE>")     //报文类型
                sb.append("     <CUSTYPE>01</CUSTYPE>")     //客户类型
                sb.append("     <TRAN_CODE>RLCOL105</TRAN_CODE>")     //交易码
                sb.append("     <LAUNCHERID>015</LAUNCHERID>")     //发起方标志
                sb.append("     <PLATID>015</PLATID>")     //平台号
                sb.append("     <REQUEST_DATE>${new java.util.Date().format('YYYYMMDD')}</REQUEST_DATE>")     //交易请求日期
                sb.append("     <REQUEST_TIME>${new java.util.Date().format('HHmmss')}</REQUEST_TIME>")     //交易请求事件
                sb.append("     <RESSYSTEM_ID>015</RESSYSTEM_ID>")     //响应方标志
//                sb.append("     <RESPOND_DATE>RESPOND_DATE</RESPOND_DATE>")     //交易响应日期
//                sb.append("     <RESPOND_TIME>RESPOND_TIME</RESPOND_TIME>")     //交易响应时间
                sb.append("     <REQ_TRACENO>${java.util.UUID.randomUUID().toString()}</REQ_TRACENO>")     //UUID 请求方必填
//                sb.append("     <RES_TRACENO>RES_TRACENO</RES_TRACENO>")     //UUID 响应方系统必填
//                sb.append("     <RETCODE>RETCODE</RETCODE>")     //交易结果返回码
//                sb.append("     <ERRORMSG>ERRORMSG</ERRORMSG>")     //错误原因
//                sb.append("     <SIGNATURE>SIGNATURE</SIGNATURE>")     //签名
//                sb.append("     <RESERVE_FIELD>RESERVE_FIELD</RESERVE_FIELD>")     //备用域
                sb.append(" </HEAD>")
                sb.append(" <BODY>")
                sb.append("     <TASK_SEQNO>${opportunity?.serialNumber}</TASK_SEQNO>")     //流水号
//                sb.append("     <BNKNO>BNKNO</BNKNO>")     //机构号
                sb.append("     <CERTY>01</CERTY>")     //证件类型
                sb.append("     <CERNO>${contact?.idNumber}</CERNO>")     //证件号码
                sb.append("     <CUSTNM>${contact?.fullName}</CUSTNM>")     //客户姓名
                sb.append("     <REALPERMBLNO>${contact?.cellphone}</REALPERMBLNO>")     //移动电话
                def loanprdcode = ["汽车分期":"PLJA","汽车衍生消费分期":"PLJJ","家装分期":"PLJM"]
                sb.append("     <LOAN_PRDCODE>${loanprdcode.get(opportunity?.product?.name)}</LOAN_PRDCODE>")     //消费场景（产品码）
                sb.append("     <LOAN_TERM>${opportunity?.loanDuration}</LOAN_TERM>")     //分期期数
//                sb.append("     <COMPANY>${}</COMPANY>")     //经销商ID
                sb.append("     <APPLYDT_START>${opportunity?.createdDate?.format("YYYYMMDD")}</APPLYDT_START>")     //申请日期-开始
                sb.append("     <APPLYDT_END>${opportunity?.actualLendingDate?.format("YYYYMMDD")}</APPLYDT_END>")     //申请日期-结束
                def scope = ["全部(包括已删除及未删除)":"0","未删除":"1","已删除":"2"]
                sb.append("     <SCOPE>${scope.get("全部(包括已删除及未删除)")}</SCOPE>")     //查询范围   todo
                def querytype = ["全部（包括线下发起申请和在线场景分期）":"00","在线场景分期":"01"]
                sb.append("     <QUERY_TYPE>${querytype?.get("全部（包括线下发起申请和在线场景分期）")}</TYPE>")     //查询类型  todo
                sb.append("     <PAGE_NUM>1</PAGE_NUM>")     //页数  todo
                sb.append(" </BODY>")
                sb.append("</MSG>")
                return String.format("%05d", sb.toString().length()) + sb.toString()
            }
            def sentHTTPRequest = { urlString, requestData, String header ->
                try
                {
                    def connection = (java.net.HttpURLConnection) urlString.openConnection()
                    connection.setDoOutput(true)
                    connection.setRequestMethod("POST")
                    connection.setRequestProperty("Content-Type", header)
                    connection.outputStream.withWriter("UTF-8") { java.io.Writer writer -> writer.write requestData }
                    connection.setConnectTimeout(60000)
                    result = grails.converters.JSON.parse(connection.inputStream.withReader("UTF-8") { java.io.Reader reader -> reader.text })
                    return result
                }
                catch (java.lang.Exception e)
                {
                    e.printStackTrace()
                    println(e)
                }
            }
            //获取token请求参数
            map = [:]
            map.code = dataMap.verifiedCode
            map.cellphone = dataMap.cellphone
            def data = getXmlInfo(map)
            println "RLCOL105发送R系统报文："+data
            if (data){
                result = sentHTTPRequest(new java.net.URL("http://5q6zif.natappfree.cc/decision/sync/get"), groovy.json.JsonOutput.toJson(map).toString(), "application/json")
                println "RLCOL104发送R系统信息返回结果：" + result
                if (result?.stateCode == "00000")
                {
                    println(["message": "RLCOL105发送R系统数据成功", "status": "成功"] as grails.converters.JSON)
                    return true
                }
                else
                {
                    println(["message": "RLCOL105发送R系统返回失败", "status": "失败"] as grails.converters.JSON)
                    return true
                }
            }else{
                println(["message": "RLCOL105订单类型错误", "status": "失败"] as grails.converters.JSON)
                return true
            }
        }
        else
        {
            println(["message": "RLCOL105获取不到订单", "status": "失败"] as grails.converters.JSON)
            return true
        }
    }
    def RLCOL106 = { dataMap ->
        def result
        def map
        com.next.Opportunity opportunity = dataMap.opportunity
        if(opportunity){
            def getXmlInfo = { map1 ->
                StringBuilder sb = new StringBuilder()
                sb.append("<?xml version='1.0' encoding='utf-8'?> standalone='yes'")
                sb.append("<MSG>")
                sb.append(" <HEAD>")
                sb.append("     <MSGTYPE>0100</MSGTYPE>")     //报文类型
                sb.append("     <CUSTYPE>01</CUSTYPE>")     //客户类型
                sb.append("     <TRAN_CODE>RLCOL106</TRAN_CODE>")     //交易码
                sb.append("     <LAUNCHERID>015</LAUNCHERID>")     //发起方标志
                sb.append("     <PLATID>015</PLATID>")     //平台号
                sb.append("     <REQUEST_DATE>${new java.util.Date().format('YYYYMMDD')}</REQUEST_DATE>")     //交易请求日期
                sb.append("     <REQUEST_TIME>${new java.util.Date().format('HHmmss')}</REQUEST_TIME>")     //交易请求事件
                sb.append("     <RESSYSTEM_ID>015</RESSYSTEM_ID>")     //响应方标志
//                sb.append("     <RESPOND_DATE>RESPOND_DATE</RESPOND_DATE>")     //交易响应日期
//                sb.append("     <RESPOND_TIME>RESPOND_TIME</RESPOND_TIME>")     //交易响应时间
                sb.append("     <REQ_TRACENO>${java.util.UUID.randomUUID().toString()}</REQ_TRACENO>")     //UUID 请求方必填
//                sb.append("     <RES_TRACENO>RES_TRACENO</RES_TRACENO>")     //UUID 响应方系统必填
//                sb.append("     <RETCODE>RETCODE</RETCODE>")     //交易结果返回码
//                sb.append("     <ERRORMSG>ERRORMSG</ERRORMSG>")     //错误原因
//                sb.append("     <SIGNATURE>SIGNATURE</SIGNATURE>")     //签名
//                sb.append("     <RESERVE_FIELD>RESERVE_FIELD</RESERVE_FIELD>")     //备用域
                sb.append(" </HEAD>")
                sb.append(" <BODY>")
                sb.append("     <TASK_SEQNO>${opportunity?.serialNumber}</TASK_SEQNO>")     //流水号
                def scope = ["全部(包括已删除及未删除)":"0","未删除":"1","已删除":"2"]
                sb.append("     <SCOPE>${scope.get("全部(包括已删除及未删除)")}</SCOPE>")     //查询范围   todo
                def querytype = ["全部（包括线下发起申请和在线场景分期）":"00","在线场景分期":"01"]
                sb.append("     <QUERY_TYPE>${querytype?.get("全部（包括线下发起申请和在线场景分期）")}</TYPE>")     //查询类型  todo
                sb.append(" </BODY>")
                sb.append("</MSG>")
                return String.format("%05d", sb.toString().length()) + sb.toString()
            }
            def sentHTTPRequest = { urlString, requestData, String header ->
                try
                {
                    def connection = (java.net.HttpURLConnection) urlString.openConnection()
                    connection.setDoOutput(true)
                    connection.setRequestMethod("POST")
                    connection.setRequestProperty("Content-Type", header)
                    connection.outputStream.withWriter("UTF-8") { java.io.Writer writer -> writer.write requestData }
                    connection.setConnectTimeout(60000)
                    result = grails.converters.JSON.parse(connection.inputStream.withReader("UTF-8") { java.io.Reader reader -> reader.text })
                    return result
                }
                catch (java.lang.Exception e)
                {
                    e.printStackTrace()
                    println(e)
                }
            }
            //获取token请求参数
            map = [:]
            map.code = dataMap.verifiedCode
            map.cellphone = dataMap.cellphone
            def data = getXmlInfo(map)
            println "RLCOL106发送R系统报文："+data
            if (data){
                result = sentHTTPRequest(new java.net.URL("http://5q6zif.natappfree.cc/decision/sync/get"), groovy.json.JsonOutput.toJson(map).toString(), "application/json")
                println "RLCOL106发送R系统信息返回结果：" + result
                if (result?.stateCode == "00000")
                {
                    println(["message": "RLCOL106发送R系统数据成功", "status": "成功"] as grails.converters.JSON)
                    return true
                }
                else
                {
                    println(["message": "RLCOL106发送R系统返回失败", "status": "失败"] as grails.converters.JSON)
                    return true
                }
            }else{
                println(["message": "RLCOL106订单类型错误", "status": "失败"] as grails.converters.JSON)
                return true
            }
        }
        else
        {
            println(["message": "RLCOL106获取不到订单", "status": "失败"] as grails.converters.JSON)
            return true
        }
    }
    def RLCOL107 = { dataMap ->
        def result
        def map
        com.next.Opportunity opportunity = dataMap.opportunity
        com.next.Contact contact = opportunity?.contact
        if(opportunity){
            def getXmlInfo = { map1 ->
                StringBuilder sb = new StringBuilder()
                sb.append("<?xml version='1.0' encoding='utf-8'?> standalone='yes'")
                sb.append("<MSG>")
                sb.append(" <HEAD>")
                sb.append("     <MSGTYPE>0100</MSGTYPE>")     //报文类型
                sb.append("     <CUSTYPE>01</CUSTYPE>")     //客户类型
                sb.append("     <TRAN_CODE>RLCOL107</TRAN_CODE>")     //交易码
                sb.append("     <LAUNCHERID>015</LAUNCHERID>")     //发起方标志
                sb.append("     <PLATID>015</PLATID>")     //平台号
                sb.append("     <REQUEST_DATE>${new java.util.Date().format('YYYYMMDD')}</REQUEST_DATE>")     //交易请求日期
                sb.append("     <REQUEST_TIME>${new java.util.Date().format('HHmmss')}</REQUEST_TIME>")     //交易请求事件
                sb.append("     <RESSYSTEM_ID>015</RESSYSTEM_ID>")     //响应方标志
//                sb.append("     <RESPOND_DATE>RESPOND_DATE</RESPOND_DATE>")     //交易响应日期
//                sb.append("     <RESPOND_TIME>RESPOND_TIME</RESPOND_TIME>")     //交易响应时间
                sb.append("     <REQ_TRACENO>${java.util.UUID.randomUUID().toString()}</REQ_TRACENO>")     //UUID 请求方必填
//                sb.append("     <RES_TRACENO>RES_TRACENO</RES_TRACENO>")     //UUID 响应方系统必填
//                sb.append("     <RETCODE>RETCODE</RETCODE>")     //交易结果返回码
//                sb.append("     <ERRORMSG>ERRORMSG</ERRORMSG>")     //错误原因
//                sb.append("     <SIGNATURE>SIGNATURE</SIGNATURE>")     //签名
//                sb.append("     <RESERVE_FIELD>RESERVE_FIELD</RESERVE_FIELD>")     //备用域
                sb.append(" </HEAD>")
                sb.append(" <BODY>")
                sb.append("     <CUSTNM>${contact?.fullName}</CUSTNM>")     //客户姓名
                sb.append("     <CERTY>01</CERTY>")     //证件类型
                sb.append("     <CERNO>${contact?.idNumber}</CERNO>")     //证件号码
                sb.append("     <HIBNK></HIBNK>")     //省行机构号 todo
                def loanprdcode = ["汽车分期":"PLJA","汽车衍生消费分期":"PLJJ","家装分期":"PLJM"]
                sb.append("     <LOANPRDCODE>${loanprdcode.get(opportunity?.product?.name)}</LOANPRDCODE>")     //贷款产品码
                sb.append("     <YEARINCOME>${new BigDecimal(contact?.monthlyIncome * 12 ).setScale(2, java.math.BigDecimal.ROUND_HALF_UP)}</YEARINCOME>")     //年收入

                sb.append("     <MONTHDEBT>${new BigDecimal(contact?.monthlyExpenses).setScale(2, java.math.BigDecimal.ROUND_HALF_UP)}</MONTHDEBT>")     //平均月负债
//                sb.append("     <COMPANY>${}</COMPANY>")     //经销商ID
                sb.append("     <LOANTERM>${opportunity?.loanDuration}</LOANTERM>")     //拟分期月数
                sb.append("     <PROVINCEID>${contact?.city?.province}</PROVINCEID>")     //省份
                sb.append("     <CITYID>${contact?.city}</CITYID>")     //城市
                sb.append("     <COMPANY></COMPANY>")     //经销商  todo
                sb.append("     <BRANDID></BRANDID>")     //品牌  todo
                sb.append("     <CARTYPEID></CARTYPEID>")     //系列  todo
                sb.append("     <CARMODELID></CARMODELID>")     //汽车车型  todo
                sb.append("     <MONTHINCOME>${new BigDecimal(contact?.monthlyTotalIncome).setScale(2, java.math.BigDecimal.ROUND_HALF_UP)}</MONTHINCOME>")     //月总收入
                sb.append("     <TOTALAMOUNT></TOTALAMOUNT>")     //购车总价
                sb.append("     <LOANAMOUNT>${new BigDecimal(opportunity?.loanAmount).setScale(2, java.math.BigDecimal.ROUND_HALF_UP)}</LOANAMOUNT>")     //贷款总额

                sb.append(" </BODY>")
                sb.append("</MSG>")
                return String.format("%05d", sb.toString().length()) + sb.toString()
            }
            def sentHTTPRequest = { urlString, requestData, String header ->
                try
                {
                    def connection = (java.net.HttpURLConnection) urlString.openConnection()
                    connection.setDoOutput(true)
                    connection.setRequestMethod("POST")
                    connection.setRequestProperty("Content-Type", header)
                    connection.outputStream.withWriter("UTF-8") { java.io.Writer writer -> writer.write requestData }
                    connection.setConnectTimeout(60000)
                    result = grails.converters.JSON.parse(connection.inputStream.withReader("UTF-8") { java.io.Reader reader -> reader.text })
                    return result
                }
                catch (java.lang.Exception e)
                {
                    e.printStackTrace()
                    println(e)
                }
            }
            //获取token请求参数
            map = [:]
            map.code = dataMap.verifiedCode
            map.cellphone = dataMap.cellphone
            def data = getXmlInfo(map)
            println "RLCOL107发送R系统报文："+data
            if (data){
                result = sentHTTPRequest(new java.net.URL("http://5q6zif.natappfree.cc/decision/sync/get"), groovy.json.JsonOutput.toJson(map).toString(), "application/json")
                println "RLCOL107发送R系统信息返回结果：" + result
                if (result?.stateCode == "00000")
                {
                    println(["message": "RLCOL107发送R系统数据成功", "status": "成功"] as grails.converters.JSON)
                    return true
                }
                else
                {
                    println(["message": "RLCOL107发送R系统返回失败", "status": "失败"] as grails.converters.JSON)
                    return true
                }
            }else{
                println(["message": "RLCOL107订单类型错误", "status": "失败"] as grails.converters.JSON)
                return true
            }
        }
        else
        {
            println(["message": "RLCOL107获取不到订单", "status": "失败"] as grails.converters.JSON)
            return true
        }
    }

    def getSeriesByBrandId()
    {
        render([list: VehicleSeries.findAllByBrand(VehicleBrand.findById(params['brandId']))] as JSON)
    }

    def getMarqueBySeriesId()
    {
        render([list: VehicleMarque.findAllBySeries(VehicleSeries.findById(params['seriesId']))] as JSON)
    }
}
